Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

vm_insnhelper.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 vm_insnhelper.c - instruction helper functions.
4
5 $Author: nagachika $
6
7 Copyright (C) 2007 Koichi Sasada
8
9 **********************************************************************/
10
11 /* finish iseq array */
12 #include "insns.inc"
13 #include <math.h>
14 #include "constant.h"
15 #include "internal.h"
16 #include "probes.h"
17 #include "probes_helper.h"
18
19 /* control stack frame */
20
21 #ifndef INLINE
22 #define INLINE inline
23 #endif
24
25 static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
26
27 static void
28 vm_stackoverflow(void)
29 {
30 rb_exc_raise(sysstack_error);
31 }
32
33 static inline rb_control_frame_t *
34 vm_push_frame(rb_thread_t *th,
35 const rb_iseq_t *iseq,
36 VALUE type,
37 VALUE self,
38 VALUE klass,
39 VALUE specval,
40 const VALUE *pc,
41 VALUE *sp,
42 int local_size,
43 const rb_method_entry_t *me)
44 {
45 rb_control_frame_t *const cfp = th->cfp - 1;
46 int i;
47
48 /* check stack overflow */
49 if ((void *)(sp + local_size) >= (void *)cfp) {
50 vm_stackoverflow();
51 }
52 th->cfp = cfp;
53
54 /* setup vm value stack */
55
56 /* initialize local variables */
57 for (i=0; i < local_size; i++) {
58 *sp++ = Qnil;
59 }
60
61 /* set special val */
62 *sp = specval;
63
64 /* setup vm control frame stack */
65
66 cfp->pc = (VALUE *)pc;
67 cfp->sp = sp + 1;
68 #if VM_DEBUG_BP_CHECK
69 cfp->bp_check = sp + 1;
70 #endif
71 cfp->ep = sp;
72 cfp->iseq = (rb_iseq_t *) iseq;
73 cfp->flag = type;
74 cfp->self = self;
75 cfp->block_iseq = 0;
76 cfp->proc = 0;
77 cfp->me = me;
78 if (klass) {
79 cfp->klass = klass;
80 }
81 else {
82 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
83 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) {
84 cfp->klass = Qnil;
85 }
86 else {
87 cfp->klass = prev_cfp->klass;
88 }
89 }
90
91 if (VMDEBUG == 2) {
92 SDR();
93 }
94
95 return cfp;
96 }
97
98 static inline void
99 vm_pop_frame(rb_thread_t *th)
100 {
101 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
102
103 if (VMDEBUG == 2) {
104 SDR();
105 }
106 }
107
108 /* method dispatch */
109 static inline VALUE
110 rb_arg_error_new(int argc, int min, int max)
111 {
112 VALUE err_mess = 0;
113 if (min == max) {
114 err_mess = rb_sprintf("wrong number of arguments (%d for %d)", argc, min);
115 }
116 else if (max == UNLIMITED_ARGUMENTS) {
117 err_mess = rb_sprintf("wrong number of arguments (%d for %d+)", argc, min);
118 }
119 else {
120 err_mess = rb_sprintf("wrong number of arguments (%d for %d..%d)", argc, min, max);
121 }
122 return rb_exc_new3(rb_eArgError, err_mess);
123 }
124
125 NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc));
126 static void
127 argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc)
128 {
129 VALUE exc = rb_arg_error_new(miss_argc, min_argc, max_argc);
130 VALUE bt = rb_make_backtrace();
131 VALUE err_line = 0;
132
133 if (iseq) {
134 int line_no = rb_iseq_first_lineno(iseq);
135
136 err_line = rb_sprintf("%s:%d:in `%s'",
137 RSTRING_PTR(iseq->location.path),
138 line_no, RSTRING_PTR(iseq->location.label));
139 rb_funcall(bt, rb_intern("unshift"), 1, err_line);
140 }
141
142 rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
143 rb_exc_raise(exc);
144 }
145
146 NORETURN(static void unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash));
147 static void
148 unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash)
149 {
150 VALUE sep = rb_usascii_str_new2(", "), keys;
151 const char *msg;
152 int i;
153 for (i = 0; i < iseq->arg_keywords; i++) {
154 rb_hash_delete(hash, ID2SYM(iseq->arg_keyword_table[i]));
155 }
156 keys = rb_funcall(hash, rb_intern("keys"), 0, 0);
157 if (!RB_TYPE_P(keys, T_ARRAY)) rb_raise(rb_eArgError, "unknown keyword");
158 msg = RARRAY_LEN(keys) == 1 ? "" : "s";
159 keys = rb_funcall(keys, rb_intern("join"), 1, sep);
160 rb_raise(rb_eArgError, "unknown keyword%s: %"PRIsVALUE, msg, keys);
161 }
162
163 void
164 rb_error_arity(int argc, int min, int max)
165 {
166 rb_exc_raise(rb_arg_error_new(argc, min, max));
167 }
168
169 /* svar */
170
171 static inline NODE *
172 lep_svar_place(rb_thread_t *th, VALUE *lep)
173 {
174 VALUE *svar;
175
176 if (lep && th->root_lep != lep) {
177 svar = &lep[-1];
178 }
179 else {
180 svar = &th->root_svar;
181 }
182 if (NIL_P(*svar)) {
183 *svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil);
184 }
185 return (NODE *)*svar;
186 }
187
188 static VALUE
189 lep_svar_get(rb_thread_t *th, VALUE *lep, rb_num_t key)
190 {
191 NODE *svar = lep_svar_place(th, lep);
192
193 switch (key) {
194 case 0:
195 return svar->u1.value;
196 case 1:
197 return svar->u2.value;
198 default: {
199 const VALUE ary = svar->u3.value;
200
201 if (NIL_P(ary)) {
202 return Qnil;
203 }
204 else {
205 return rb_ary_entry(ary, key - DEFAULT_SPECIAL_VAR_COUNT);
206 }
207 }
208 }
209 }
210
211 static void
212 lep_svar_set(rb_thread_t *th, VALUE *lep, rb_num_t key, VALUE val)
213 {
214 NODE *svar = lep_svar_place(th, lep);
215
216 switch (key) {
217 case 0:
218 svar->u1.value = val;
219 return;
220 case 1:
221 svar->u2.value = val;
222 return;
223 default: {
224 VALUE ary = svar->u3.value;
225
226 if (NIL_P(ary)) {
227 svar->u3.value = ary = rb_ary_new();
228 }
229 rb_ary_store(ary, key - DEFAULT_SPECIAL_VAR_COUNT, val);
230 }
231 }
232 }
233
234 static inline VALUE
235 vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
236 {
237 VALUE val;
238
239 if (type == 0) {
240 val = lep_svar_get(th, lep, key);
241 }
242 else {
243 VALUE backref = lep_svar_get(th, lep, 1);
244
245 if (type & 0x01) {
246 switch (type >> 1) {
247 case '&':
248 val = rb_reg_last_match(backref);
249 break;
250 case '`':
251 val = rb_reg_match_pre(backref);
252 break;
253 case '\'':
254 val = rb_reg_match_post(backref);
255 break;
256 case '+':
257 val = rb_reg_match_last(backref);
258 break;
259 default:
260 rb_bug("unexpected back-ref");
261 }
262 }
263 else {
264 val = rb_reg_nth_match((int)(type >> 1), backref);
265 }
266 }
267 return val;
268 }
269
270 static NODE *
271 vm_get_cref0(const rb_iseq_t *iseq, const VALUE *ep)
272 {
273 while (1) {
274 if (VM_EP_LEP_P(ep)) {
275 if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL;
276 return iseq->cref_stack;
277 }
278 else if (ep[-1] != Qnil) {
279 return (NODE *)ep[-1];
280 }
281 ep = VM_EP_PREV_EP(ep);
282 }
283 }
284
285 NODE *
286 rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *ep)
287 {
288 NODE *cref = vm_get_cref0(iseq, ep);
289
290 if (cref == 0) {
291 rb_bug("rb_vm_get_cref: unreachable");
292 }
293 return cref;
294 }
295
296 static NODE *
297 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
298 {
299 rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
300 NODE *cref = NEW_CREF(klass);
301 cref->nd_refinements = Qnil;
302 cref->nd_visi = noex;
303
304 if (blockptr) {
305 cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->ep);
306 }
307 else if (cfp) {
308 cref->nd_next = vm_get_cref0(cfp->iseq, cfp->ep);
309 }
310 /* TODO: why cref->nd_next is 1? */
311 if (cref->nd_next && cref->nd_next != (void *) 1 &&
312 !NIL_P(cref->nd_next->nd_refinements)) {
313 COPY_CREF_OMOD(cref, cref->nd_next);
314 }
315
316 return cref;
317 }
318
319 static inline VALUE
320 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep)
321 {
322 NODE *cref = rb_vm_get_cref(iseq, ep);
323 VALUE klass = Qundef;
324
325 while (cref) {
326 if ((klass = cref->nd_clss) != 0) {
327 break;
328 }
329 cref = cref->nd_next;
330 }
331
332 return klass;
333 }
334
335 static inline VALUE
336 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *ep)
337 {
338 NODE *cref = rb_vm_get_cref(iseq, ep);
339 VALUE klass = Qundef;
340
341 while (cref) {
342 if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) &&
343 (klass = cref->nd_clss) != 0) {
344 break;
345 }
346 cref = cref->nd_next;
347 }
348
349 return klass;
350 }
351
352 static inline void
353 vm_check_if_namespace(VALUE klass)
354 {
355 VALUE str;
356 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE)) {
357 str = rb_inspect(klass);
358 rb_raise(rb_eTypeError, "%s is not a class/module",
359 StringValuePtr(str));
360 }
361 }
362
363 static inline VALUE
364 vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
365 {
366 if (RB_TYPE_P(klass, T_MODULE) &&
367 FL_TEST(klass, RMODULE_IS_OVERLAID) &&
368 RB_TYPE_P(cfp->klass, T_ICLASS) &&
369 RBASIC(cfp->klass)->klass == klass) {
370 return cfp->klass;
371 }
372 else {
373 return klass;
374 }
375 }
376
377 static inline VALUE
378 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
379 VALUE orig_klass, ID id, int is_defined)
380 {
381 VALUE val;
382
383 if (orig_klass == Qnil) {
384 /* in current lexical scope */
385 const NODE *root_cref = rb_vm_get_cref(iseq, th->cfp->ep);
386 const NODE *cref;
387 VALUE klass = orig_klass;
388
389 while (root_cref && root_cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) {
390 root_cref = root_cref->nd_next;
391 }
392 cref = root_cref;
393 while (cref && cref->nd_next) {
394 if (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) {
395 klass = Qnil;
396 }
397 else {
398 klass = cref->nd_clss;
399 }
400 cref = cref->nd_next;
401
402 if (!NIL_P(klass)) {
403 VALUE av, am = 0;
404 st_data_t data;
405 search_continue:
406 if (RCLASS_CONST_TBL(klass) &&
407 st_lookup(RCLASS_CONST_TBL(klass), id, &data)) {
408 val = ((rb_const_entry_t*)data)->value;
409 if (val == Qundef) {
410 if (am == klass) break;
411 am = klass;
412 if (is_defined) return 1;
413 if (rb_autoloading_value(klass, id, &av)) return av;
414 rb_autoload_load(klass, id);
415 goto search_continue;
416 }
417 else {
418 if (is_defined) {
419 return 1;
420 }
421 else {
422 return val;
423 }
424 }
425 }
426 }
427 }
428
429 /* search self */
430 if (root_cref && !NIL_P(root_cref->nd_clss)) {
431 klass = vm_get_iclass(th->cfp, root_cref->nd_clss);
432 }
433 else {
434 klass = CLASS_OF(th->cfp->self);
435 }
436
437 if (is_defined) {
438 return rb_const_defined(klass, id);
439 }
440 else {
441 return rb_const_get(klass, id);
442 }
443 }
444 else {
445 vm_check_if_namespace(orig_klass);
446 if (is_defined) {
447 return rb_public_const_defined_from(orig_klass, id);
448 }
449 else {
450 return rb_public_const_get_from(orig_klass, id);
451 }
452 }
453 }
454
455 static inline VALUE
456 vm_get_cvar_base(NODE *cref, rb_control_frame_t *cfp)
457 {
458 VALUE klass;
459
460 if (!cref) {
461 rb_bug("vm_get_cvar_base: no cref");
462 }
463
464 while (cref->nd_next &&
465 (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) ||
466 (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) {
467 cref = cref->nd_next;
468 }
469 if (!cref->nd_next) {
470 rb_warn("class variable access from toplevel");
471 }
472
473 klass = vm_get_iclass(cfp, cref->nd_clss);
474
475 if (NIL_P(klass)) {
476 rb_raise(rb_eTypeError, "no class variables available");
477 }
478 return klass;
479 }
480
481 static VALUE
482 vm_search_const_defined_class(const VALUE cbase, ID id)
483 {
484 if (rb_const_defined_at(cbase, id)) return cbase;
485 if (cbase == rb_cObject) {
486 VALUE tmp = RCLASS_SUPER(cbase);
487 while (tmp) {
488 if (rb_const_defined_at(tmp, id)) return tmp;
489 tmp = RCLASS_SUPER(tmp);
490 }
491 }
492 return 0;
493 }
494
495 #ifndef USE_IC_FOR_IVAR
496 #define USE_IC_FOR_IVAR 1
497 #endif
498
499 static inline VALUE
500 vm_getivar(VALUE obj, ID id, IC ic, rb_call_info_t *ci, int is_attr)
501 {
502 #if USE_IC_FOR_IVAR
503 if (RB_TYPE_P(obj, T_OBJECT)) {
504 VALUE val = Qundef;
505 VALUE klass = RBASIC(obj)->klass;
506
507 if (LIKELY((!is_attr && (ic->ic_class == klass && ic->ic_vmstat == GET_VM_STATE_VERSION())) ||
508 (is_attr && ci->aux.index > 0))) {
509 long index = !is_attr ? ic->ic_value.index : ci->aux.index - 1;
510 long len = ROBJECT_NUMIV(obj);
511 VALUE *ptr = ROBJECT_IVPTR(obj);
512
513 if (index < len) {
514 val = ptr[index];
515 }
516 }
517 else {
518 st_data_t index;
519 long len = ROBJECT_NUMIV(obj);
520 VALUE *ptr = ROBJECT_IVPTR(obj);
521 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
522
523 if (iv_index_tbl) {
524 if (st_lookup(iv_index_tbl, id, &index)) {
525 if ((long)index < len) {
526 val = ptr[index];
527 }
528 if (!is_attr) {
529 ic->ic_class = klass;
530 ic->ic_value.index = index;
531 ic->ic_vmstat = GET_VM_STATE_VERSION();
532 }
533 else { /* call_info */
534 ci->aux.index = index + 1;
535 }
536 }
537 }
538 }
539
540 if (UNLIKELY(val == Qundef)) {
541 if (!is_attr) rb_warning("instance variable %s not initialized", rb_id2name(id));
542 val = Qnil;
543 }
544 return val;
545 }
546 #endif /* USE_IC_FOR_IVAR */
547 if (is_attr)
548 return rb_attr_get(obj, id);
549 return rb_ivar_get(obj, id);
550 }
551
552 static inline VALUE
553 vm_setivar(VALUE obj, ID id, VALUE val, IC ic, rb_call_info_t *ci, int is_attr)
554 {
555 #if USE_IC_FOR_IVAR
556 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) {
557 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
558 }
559
560 rb_check_frozen(obj);
561
562 if (RB_TYPE_P(obj, T_OBJECT)) {
563 VALUE klass = RBASIC(obj)->klass;
564 st_data_t index;
565
566 if (LIKELY(
567 (!is_attr && ic->ic_class == klass && ic->ic_vmstat == GET_VM_STATE_VERSION()) ||
568 (is_attr && ci->aux.index > 0))) {
569 long index = !is_attr ? ic->ic_value.index : ci->aux.index-1;
570 long len = ROBJECT_NUMIV(obj);
571 VALUE *ptr = ROBJECT_IVPTR(obj);
572
573 if (index < len) {
574 ptr[index] = val;
575 return val; /* inline cache hit */
576 }
577 }
578 else {
579 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
580
581 if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
582 if (!is_attr) {
583 ic->ic_class = klass;
584 ic->ic_value.index = index;
585 ic->ic_vmstat = GET_VM_STATE_VERSION();
586 }
587 else {
588 ci->aux.index = index + 1;
589 }
590 }
591 /* fall through */
592 }
593 }
594 #endif /* USE_IC_FOR_IVAR */
595 return rb_ivar_set(obj, id, val);
596 }
597
598 static VALUE
599 vm_getinstancevariable(VALUE obj, ID id, IC ic)
600 {
601 return vm_getivar(obj, id, ic, 0, 0);
602 }
603
604 static void
605 vm_setinstancevariable(VALUE obj, ID id, VALUE val, IC ic)
606 {
607 vm_setivar(obj, id, val, ic, 0, 0);
608 }
609
610 static VALUE
611 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
612 rb_num_t throw_state, VALUE throwobj)
613 {
614 int state = (int)(throw_state & 0xff);
615 int flag = (int)(throw_state & 0x8000);
616 rb_num_t level = throw_state >> 16;
617
618 if (state != 0) {
619 VALUE *pt = 0;
620 if (flag != 0) {
621 pt = (void *) 1;
622 }
623 else {
624 if (state == TAG_BREAK) {
625 rb_control_frame_t *cfp = GET_CFP();
626 VALUE *ep = GET_EP();
627 int is_orphan = 1;
628 rb_iseq_t *base_iseq = GET_ISEQ();
629
630 search_parent:
631 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
632 if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
633 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
634 ep = cfp->ep;
635 goto search_parent;
636 }
637 ep = VM_EP_PREV_EP(ep);
638 base_iseq = base_iseq->parent_iseq;
639
640 while ((VALUE *) cfp < th->stack + th->stack_size) {
641 if (cfp->ep == ep) {
642 goto search_parent;
643 }
644 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
645 }
646 rb_bug("VM (throw): can't find break base.");
647 }
648
649 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
650 /* lambda{... break ...} */
651 is_orphan = 0;
652 pt = cfp->ep;
653 state = TAG_RETURN;
654 }
655 else {
656 ep = VM_EP_PREV_EP(ep);
657
658 while ((VALUE *)cfp < th->stack + th->stack_size) {
659 if (cfp->ep == ep) {
660 VALUE epc = cfp->pc - cfp->iseq->iseq_encoded;
661 rb_iseq_t *iseq = cfp->iseq;
662 int i;
663
664 for (i=0; i<iseq->catch_table_size; i++) {
665 struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
666
667 if (entry->type == CATCH_TYPE_BREAK &&
668 entry->start < epc && entry->end >= epc) {
669 if (entry->cont == epc) {
670 goto found;
671 }
672 else {
673 break;
674 }
675 }
676 }
677 break;
678
679 found:
680 pt = ep;
681 is_orphan = 0;
682 break;
683 }
684 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
685 }
686 }
687
688 if (is_orphan) {
689 rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
690 }
691 }
692 else if (state == TAG_RETRY) {
693 rb_num_t i;
694 pt = VM_EP_PREV_EP(GET_EP());
695 for (i = 0; i < level; i++) {
696 pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
697 }
698 }
699 else if (state == TAG_RETURN) {
700 rb_control_frame_t *cfp = GET_CFP();
701 VALUE *ep = GET_EP();
702 VALUE *target_lep = VM_CF_LEP(cfp);
703 int in_class_frame = 0;
704
705 /* check orphan and get dfp */
706 while ((VALUE *) cfp < th->stack + th->stack_size) {
707 VALUE *lep = VM_CF_LEP(cfp);
708
709 if (!target_lep) {
710 target_lep = lep;
711 }
712
713 if (lep == target_lep && cfp->iseq->type == ISEQ_TYPE_CLASS) {
714 in_class_frame = 1;
715 target_lep = 0;
716 }
717
718 if (lep == target_lep) {
719 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
720 VALUE *tep = ep;
721
722 if (in_class_frame) {
723 /* lambda {class A; ... return ...; end} */
724 ep = cfp->ep;
725 goto valid_return;
726 }
727
728 while (target_lep != tep) {
729 if (cfp->ep == tep) {
730 /* in lambda */
731 ep = cfp->ep;
732 goto valid_return;
733 }
734 tep = VM_EP_PREV_EP(tep);
735 }
736 }
737 }
738
739 if (cfp->ep == target_lep && cfp->iseq->type == ISEQ_TYPE_METHOD) {
740 ep = target_lep;
741 goto valid_return;
742 }
743
744 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
745 }
746
747 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
748
749 valid_return:
750 pt = ep;
751 }
752 else {
753 rb_bug("isns(throw): unsupport throw type");
754 }
755 }
756 th->state = state;
757 return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
758 }
759 else {
760 /* continue throw */
761 VALUE err = throwobj;
762
763 if (FIXNUM_P(err)) {
764 th->state = FIX2INT(err);
765 }
766 else if (SYMBOL_P(err)) {
767 th->state = TAG_THROW;
768 }
769 else if (BUILTIN_TYPE(err) == T_NODE) {
770 th->state = GET_THROWOBJ_STATE(err);
771 }
772 else {
773 th->state = TAG_RAISE;
774 /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
775 }
776 return err;
777 }
778 }
779
780 static inline void
781 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag)
782 {
783 int is_splat = flag & 0x01;
784 rb_num_t space_size = num + is_splat;
785 VALUE *base = cfp->sp, *ptr;
786 rb_num_t len;
787
788 if (!RB_TYPE_P(ary, T_ARRAY)) {
789 ary = rb_ary_to_ary(ary);
790 }
791
792 cfp->sp += space_size;
793
794 ptr = RARRAY_PTR(ary);
795 len = (rb_num_t)RARRAY_LEN(ary);
796
797 if (flag & 0x02) {
798 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
799 rb_num_t i = 0, j;
800
801 if (len < num) {
802 for (i=0; i<num-len; i++) {
803 *base++ = Qnil;
804 }
805 }
806 for (j=0; i<num; i++, j++) {
807 VALUE v = ptr[len - j - 1];
808 *base++ = v;
809 }
810 if (is_splat) {
811 *base = rb_ary_new4(len - j, ptr);
812 }
813 }
814 else {
815 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
816 rb_num_t i;
817 VALUE *bptr = &base[space_size - 1];
818
819 for (i=0; i<num; i++) {
820 if (len <= i) {
821 for (; i<num; i++) {
822 *bptr-- = Qnil;
823 }
824 break;
825 }
826 *bptr-- = ptr[i];
827 }
828 if (is_splat) {
829 if (num > len) {
830 *bptr = rb_ary_new();
831 }
832 else {
833 *bptr = rb_ary_new4(len - num, ptr + num);
834 }
835 }
836 }
837 RB_GC_GUARD(ary);
838 }
839
840 static VALUE vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
841
842 static void
843 vm_search_method(rb_call_info_t *ci, VALUE recv)
844 {
845 VALUE klass = CLASS_OF(recv);
846
847 #if OPT_INLINE_METHOD_CACHE
848 if (LIKELY(GET_VM_STATE_VERSION() == ci->vmstat && klass == ci->klass)) {
849 /* cache hit! */
850 }
851 else {
852 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
853 ci->klass = klass;
854 ci->vmstat = GET_VM_STATE_VERSION();
855 ci->call = vm_call_general;
856 }
857 #else
858 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
859 ci->call = vm_call_general;
860 ci->klass = klass;
861 #endif
862 }
863
864 static inline int
865 check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
866 {
867 if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
868 me->def->body.cfunc.func == func) {
869 return 1;
870 }
871 else {
872 return 0;
873 }
874 }
875
876 static
877 #ifndef NO_BIG_INLINE
878 inline
879 #endif
880 VALUE
881 opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci)
882 {
883 if (FIXNUM_2_P(recv, obj) &&
884 BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) {
885 return (recv == obj) ? Qtrue : Qfalse;
886 }
887 else if (FLONUM_2_P(recv, obj) &&
888 BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) {
889 return (recv == obj) ? Qtrue : Qfalse;
890 }
891 else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
892 if (HEAP_CLASS_OF(recv) == rb_cFloat &&
893 HEAP_CLASS_OF(obj) == rb_cFloat &&
894 BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) {
895 double a = RFLOAT_VALUE(recv);
896 double b = RFLOAT_VALUE(obj);
897
898 if (isnan(a) || isnan(b)) {
899 return Qfalse;
900 }
901 return (a == b) ? Qtrue : Qfalse;
902 }
903 else if (HEAP_CLASS_OF(recv) == rb_cString &&
904 HEAP_CLASS_OF(obj) == rb_cString &&
905 BASIC_OP_UNREDEFINED_P(BOP_EQ, STRING_REDEFINED_OP_FLAG)) {
906 return rb_str_equal(recv, obj);
907 }
908 }
909
910 {
911 vm_search_method(ci, recv);
912
913 if (check_cfunc(ci->me, rb_obj_equal)) {
914 return recv == obj ? Qtrue : Qfalse;
915 }
916 }
917
918 return Qundef;
919 }
920
921 static VALUE
922 check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
923 {
924 switch (type) {
925 case VM_CHECKMATCH_TYPE_WHEN:
926 return pattern;
927 case VM_CHECKMATCH_TYPE_CASE:
928 return rb_funcall2(pattern, idEqq, 1, &target);
929 case VM_CHECKMATCH_TYPE_RESCUE: {
930 if (!rb_obj_is_kind_of(pattern, rb_cModule)) {
931 rb_raise(rb_eTypeError, "class or module required for rescue clause");
932 }
933 return RTEST(rb_funcall2(pattern, idEqq, 1, &target));
934 }
935 default:
936 rb_bug("check_match: unreachable");
937 }
938 }
939
940
941 #if defined(_MSC_VER) && _MSC_VER < 1300
942 #define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse;
943 #else
944 #define CHECK_CMP_NAN(a, b) /* do nothing */
945 #endif
946
947 static inline VALUE
948 double_cmp_lt(double a, double b)
949 {
950 CHECK_CMP_NAN(a, b);
951 return a < b ? Qtrue : Qfalse;
952 }
953
954 static inline VALUE
955 double_cmp_le(double a, double b)
956 {
957 CHECK_CMP_NAN(a, b);
958 return a <= b ? Qtrue : Qfalse;
959 }
960
961 static inline VALUE
962 double_cmp_gt(double a, double b)
963 {
964 CHECK_CMP_NAN(a, b);
965 return a > b ? Qtrue : Qfalse;
966 }
967
968 static inline VALUE
969 double_cmp_ge(double a, double b)
970 {
971 CHECK_CMP_NAN(a, b);
972 return a >= b ? Qtrue : Qfalse;
973 }
974
975 static VALUE *
976 vm_base_ptr(rb_control_frame_t *cfp)
977 {
978 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
979 VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1;
980
981 if (cfp->iseq->type == ISEQ_TYPE_METHOD) {
982 /* adjust `self' */
983 bp += 1;
984 }
985
986 #if VM_DEBUG_BP_CHECK
987 if (bp != cfp->bp_check) {
988 fprintf(stderr, "bp_check: %ld, bp: %ld\n",
989 (long)(cfp->bp_check - GET_THREAD()->stack),
990 (long)(bp - GET_THREAD()->stack));
991 rb_bug("vm_base_ptr: unreachable");
992 }
993 #endif
994
995 return bp;
996 }
997
998 /* method call processes with call_info */
999
1000 static void
1001 vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1002 {
1003 #define SAVE_RESTORE_CI(expr, ci) do { \
1004 int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \
1005 expr; \
1006 (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \
1007 } while (0)
1008
1009 if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) {
1010 rb_proc_t *po;
1011 VALUE proc;
1012
1013 proc = *(--cfp->sp);
1014
1015 if (proc != Qnil) {
1016 if (!rb_obj_is_proc(proc)) {
1017 VALUE b;
1018
1019 SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci);
1020
1021 if (NIL_P(b) || !rb_obj_is_proc(b)) {
1022 rb_raise(rb_eTypeError,
1023 "wrong argument type %s (expected Proc)",
1024 rb_obj_classname(proc));
1025 }
1026 proc = b;
1027 }
1028 GetProcPtr(proc, po);
1029 ci->blockptr = &po->block;
1030 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
1031 }
1032 }
1033 else if (ci->blockiseq != 0) { /* likely */
1034 ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
1035 ci->blockptr->iseq = ci->blockiseq;
1036 ci->blockptr->proc = 0;
1037 }
1038
1039 /* expand top of stack? */
1040
1041 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) {
1042 VALUE ary = *(cfp->sp - 1);
1043 VALUE *ptr;
1044 int i;
1045 VALUE tmp;
1046
1047 SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci);
1048
1049 if (NIL_P(tmp)) {
1050 /* do nothing */
1051 }
1052 else {
1053 long len = RARRAY_LEN(tmp);
1054 ptr = RARRAY_PTR(tmp);
1055 cfp->sp -= 1;
1056
1057 CHECK_VM_STACK_OVERFLOW(cfp, len);
1058
1059 for (i = 0; i < len; i++) {
1060 *cfp->sp++ = ptr[i];
1061 }
1062 ci->argc += i-1;
1063 }
1064 }
1065 }
1066
1067 static int
1068 separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
1069 {
1070 VALUE *kwdhash = (VALUE *)arg;
1071
1072 if (!SYMBOL_P(key)) kwdhash++;
1073 if (!*kwdhash) *kwdhash = rb_hash_new();
1074 rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
1075 return ST_CONTINUE;
1076 }
1077
1078 static VALUE
1079 extract_keywords(VALUE *orighash)
1080 {
1081 VALUE parthash[2] = {0, 0};
1082 VALUE hash = *orighash;
1083
1084 if (RHASH_EMPTY_P(hash)) {
1085 *orighash = 0;
1086 return hash;
1087 }
1088 st_foreach(RHASH_TBL(hash), separate_symbol, (st_data_t)&parthash);
1089 *orighash = parthash[1];
1090 return parthash[0];
1091 }
1092
1093 static inline int
1094 vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd)
1095 {
1096 VALUE keyword_hash, orig_hash;
1097 int i, j;
1098
1099 if (argc > m &&
1100 !NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) &&
1101 (keyword_hash = extract_keywords(&orig_hash)) != 0) {
1102 if (!orig_hash) {
1103 argc--;
1104 }
1105 else {
1106 orig_argv[argc-1] = orig_hash;
1107 }
1108 if (iseq->arg_keyword_check) {
1109 for (i = j = 0; i < iseq->arg_keywords; i++) {
1110 if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++;
1111 }
1112 if (RHASH_TBL(keyword_hash)->num_entries > (unsigned int) j) {
1113 unknown_keyword_error(iseq, keyword_hash);
1114 }
1115 }
1116 }
1117 else {
1118 keyword_hash = rb_hash_new();
1119 }
1120
1121 *kwd = keyword_hash;
1122
1123 return argc;
1124 }
1125
1126 static inline int
1127 vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *orig_argv)
1128 {
1129 const int m = iseq->argc;
1130 const int opts = iseq->arg_opts - (iseq->arg_opts > 0);
1131 const int min = m + iseq->arg_post_len;
1132 const int max = (iseq->arg_rest == -1) ? m + opts + iseq->arg_post_len : UNLIMITED_ARGUMENTS;
1133 const int orig_argc = ci->argc;
1134 int argc = orig_argc;
1135 VALUE *argv = orig_argv;
1136 VALUE keyword_hash = Qnil;
1137 rb_num_t opt_pc = 0;
1138
1139 th->mark_stack_len = argc + iseq->arg_size;
1140
1141 /* keyword argument */
1142 if (iseq->arg_keyword != -1) {
1143 argc = vm_callee_setup_keyword_arg(iseq, argc, m, orig_argv, &keyword_hash);
1144 }
1145
1146 /* mandatory */
1147 if ((argc < min) || (argc > max && max != UNLIMITED_ARGUMENTS)) {
1148 argument_error(iseq, argc, min, max);
1149 }
1150
1151 argv += m;
1152 argc -= m;
1153
1154 /* post arguments */
1155 if (iseq->arg_post_len) {
1156 if (!(orig_argc < iseq->arg_post_start)) {
1157 VALUE *new_argv = ALLOCA_N(VALUE, argc);
1158 MEMCPY(new_argv, argv, VALUE, argc);
1159 argv = new_argv;
1160 }
1161
1162 MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len],
1163 VALUE, iseq->arg_post_len);
1164 }
1165
1166 /* opt arguments */
1167 if (iseq->arg_opts) {
1168 if (argc > opts) {
1169 argc -= opts;
1170 argv += opts;
1171 opt_pc = iseq->arg_opt_table[opts]; /* no opt */
1172 }
1173 else {
1174 int i;
1175 for (i = argc; i<opts; i++) {
1176 orig_argv[i + m] = Qnil;
1177 }
1178 opt_pc = iseq->arg_opt_table[argc];
1179 argc = 0;
1180 }
1181 }
1182
1183 /* rest arguments */
1184 if (iseq->arg_rest != -1) {
1185 orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv);
1186 argc = 0;
1187 }
1188
1189 /* keyword argument */
1190 if (iseq->arg_keyword != -1) {
1191 orig_argv[iseq->arg_keyword] = keyword_hash;
1192 }
1193
1194 /* block arguments */
1195 if (iseq->arg_block != -1) {
1196 VALUE blockval = Qnil;
1197 const rb_block_t *blockptr = ci->blockptr;
1198
1199 if (blockptr) {
1200 /* make Proc object */
1201 if (blockptr->proc == 0) {
1202 rb_proc_t *proc;
1203 blockval = rb_vm_make_proc(th, blockptr, rb_cProc);
1204 GetProcPtr(blockval, proc);
1205 ci->blockptr = &proc->block;
1206 }
1207 else {
1208 blockval = blockptr->proc;
1209 }
1210 }
1211
1212 orig_argv[iseq->arg_block] = blockval; /* Proc or nil */
1213 }
1214
1215 th->mark_stack_len = 0;
1216 return (int)opt_pc;
1217 }
1218
1219 static VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
1220 static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
1221 static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
1222
1223 #define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \
1224 if (LIKELY((iseq)->arg_simple & 0x01)) { \
1225 /* simple check */ \
1226 if ((ci)->argc != (iseq)->argc) { \
1227 argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \
1228 } \
1229 (ci)->aux.opt_pc = 0; \
1230 CI_SET_FASTPATH((ci), UNLIKELY((ci)->flag & VM_CALL_TAILCALL) ? vm_call_iseq_setup_tailcall : vm_call_iseq_setup_normal, !(is_lambda) && !((ci)->me->flag & NOEX_PROTECTED)); \
1231 } \
1232 else { \
1233 (ci)->aux.opt_pc = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \
1234 }
1235
1236 static VALUE
1237 vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1238 {
1239 VM_CALLEE_SETUP_ARG(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0);
1240 return vm_call_iseq_setup_2(th, cfp, ci);
1241 }
1242
1243 static VALUE
1244 vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1245 {
1246 if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) {
1247 return vm_call_iseq_setup_normal(th, cfp, ci);
1248 }
1249 else {
1250 return vm_call_iseq_setup_tailcall(th, cfp, ci);
1251 }
1252 }
1253
1254 static inline VALUE
1255 vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1256 {
1257 int i;
1258 VALUE *argv = cfp->sp - ci->argc;
1259 rb_iseq_t *iseq = ci->me->def->body.iseq;
1260 VALUE *sp = argv + iseq->arg_size;
1261
1262 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max);
1263
1264 /* clear local variables */
1265 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
1266 *sp++ = Qnil;
1267 }
1268
1269 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class,
1270 VM_ENVVAL_BLOCK_PTR(ci->blockptr),
1271 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me);
1272
1273 cfp->sp = argv - 1 /* recv */;
1274 return Qundef;
1275 }
1276
1277 static inline VALUE
1278 vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1279 {
1280 int i;
1281 VALUE *argv = cfp->sp - ci->argc;
1282 rb_iseq_t *iseq = ci->me->def->body.iseq;
1283 VALUE *src_argv = argv;
1284 VALUE *sp_orig, *sp;
1285 VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
1286
1287 cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */
1288
1289 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max);
1290 RUBY_VM_CHECK_INTS(th);
1291
1292 sp_orig = sp = cfp->sp;
1293
1294 /* push self */
1295 sp[0] = ci->recv;
1296 sp++;
1297
1298 /* copy arguments */
1299 for (i=0; i < iseq->arg_size; i++) {
1300 *sp++ = src_argv[i];
1301 }
1302
1303 /* clear local variables */
1304 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
1305 *sp++ = Qnil;
1306 }
1307
1308 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag,
1309 ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr),
1310 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me);
1311
1312 cfp->sp = sp_orig;
1313 return Qundef;
1314 }
1315
1316 static VALUE
1317 call_cfunc_m2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1318 {
1319 return (*func)(recv, rb_ary_new4(argc, argv));
1320 }
1321
1322 static VALUE
1323 call_cfunc_m1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1324 {
1325 return (*func)(argc, argv, recv);
1326 }
1327
1328 static VALUE
1329 call_cfunc_0(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1330 {
1331 return (*func)(recv);
1332 }
1333
1334 static VALUE
1335 call_cfunc_1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1336 {
1337 return (*func)(recv, argv[0]);
1338 }
1339
1340 static VALUE
1341 call_cfunc_2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1342 {
1343 return (*func)(recv, argv[0], argv[1]);
1344 }
1345
1346 static VALUE
1347 call_cfunc_3(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1348 {
1349 return (*func)(recv, argv[0], argv[1], argv[2]);
1350 }
1351
1352 static VALUE
1353 call_cfunc_4(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1354 {
1355 return (*func)(recv, argv[0], argv[1], argv[2], argv[3]);
1356 }
1357
1358 static VALUE
1359 call_cfunc_5(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1360 {
1361 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
1362 }
1363
1364 static VALUE
1365 call_cfunc_6(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1366 {
1367 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
1368 }
1369
1370 static VALUE
1371 call_cfunc_7(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1372 {
1373 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
1374 }
1375
1376 static VALUE
1377 call_cfunc_8(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1378 {
1379 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
1380 }
1381
1382 static VALUE
1383 call_cfunc_9(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1384 {
1385 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
1386 }
1387
1388 static VALUE
1389 call_cfunc_10(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1390 {
1391 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
1392 }
1393
1394 static VALUE
1395 call_cfunc_11(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1396 {
1397 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
1398 }
1399
1400 static VALUE
1401 call_cfunc_12(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1402 {
1403 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
1404 }
1405
1406 static VALUE
1407 call_cfunc_13(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1408 {
1409 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
1410 }
1411
1412 static VALUE
1413 call_cfunc_14(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1414 {
1415 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
1416 }
1417
1418 static VALUE
1419 call_cfunc_15(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
1420 {
1421 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
1422 }
1423
1424 #ifndef VM_PROFILE
1425 #define VM_PROFILE 0
1426 #endif
1427
1428 #if VM_PROFILE
1429 static int vm_profile_counter[4];
1430 #define VM_PROFILE_UP(x) (vm_profile_counter[x]++)
1431 #define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result)
1432 static void vm_profile_show_result(void)
1433 {
1434 fprintf(stderr, "VM Profile results: \n");
1435 fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]);
1436 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]);
1437 fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]);
1438 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]);
1439 }
1440 #else
1441 #define VM_PROFILE_UP(x)
1442 #define VM_PROFILE_ATEXIT()
1443 #endif
1444
1445 static VALUE
1446 vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1447 {
1448 VALUE val;
1449 const rb_method_entry_t *me = ci->me;
1450 const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
1451 int len = cfunc->argc;
1452
1453 /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
1454 VALUE recv = ci->recv;
1455 VALUE defined_class = ci->defined_class;
1456 rb_block_t *blockptr = ci->blockptr;
1457 int argc = ci->argc;
1458
1459 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
1460 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
1461
1462 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
1463 VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me);
1464
1465 if (len >= 0) rb_check_arity(argc, len, len);
1466
1467 reg_cfp->sp -= argc + 1;
1468 VM_PROFILE_UP(0);
1469 val = (*cfunc->invoker)(cfunc->func, recv, argc, reg_cfp->sp + 1);
1470
1471 if (reg_cfp != th->cfp + 1) {
1472 rb_bug("vm_call_cfunc - cfp consistency error");
1473 }
1474
1475 vm_pop_frame(th);
1476
1477 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
1478 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
1479
1480 return val;
1481 }
1482
1483 #if OPT_CALL_CFUNC_WITHOUT_FRAME
1484 static VALUE
1485 vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1486 {
1487 VALUE val;
1488 int argc = ci->argc;
1489 VALUE *argv = STACK_ADDR_FROM_TOP(argc);
1490 const rb_method_cfunc_t *cfunc = &ci->me->def->body.cfunc;
1491
1492 th->passed_ci = ci;
1493 reg_cfp->sp -= argc + 1;
1494 ci->aux.inc_sp = argc + 1;
1495 VM_PROFILE_UP(0);
1496 val = (*cfunc->invoker)(cfunc->func, ci, argv);
1497
1498 /* check */
1499 if (reg_cfp == th->cfp) { /* no frame push */
1500 if (UNLIKELY(th->passed_ci != ci)) {
1501 rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci);
1502 }
1503 th->passed_ci = 0;
1504 }
1505 else {
1506 if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) {
1507 rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1);
1508 }
1509 vm_pop_frame(th);
1510 VM_PROFILE_UP(1);
1511 }
1512
1513 return val;
1514 }
1515
1516 static VALUE
1517 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1518 {
1519 VALUE val;
1520 const rb_method_entry_t *me = ci->me;
1521 int len = me->def->body.cfunc.argc;
1522 VALUE recv = ci->recv;
1523
1524 if (len >= 0) rb_check_arity(ci->argc, len, len);
1525
1526 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
1527 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil);
1528
1529 if (!(ci->me->flag & NOEX_PROTECTED) &&
1530 !(ci->flag & VM_CALL_ARGS_SPLAT)) {
1531 CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1);
1532 }
1533 val = vm_call_cfunc_latter(th, reg_cfp, ci);
1534
1535 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
1536 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
1537
1538 return val;
1539 }
1540
1541 void
1542 vm_call_cfunc_push_frame(rb_thread_t *th)
1543 {
1544 rb_call_info_t *ci = th->passed_ci;
1545 const rb_method_entry_t *me = ci->me;
1546 th->passed_ci = 0;
1547
1548 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
1549 VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me);
1550
1551 if (ci->call != vm_call_general) {
1552 ci->call = vm_call_cfunc_with_frame;
1553 }
1554 }
1555 #else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
1556 static VALUE
1557 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1558 {
1559 return vm_call_cfunc_with_frame(th, reg_cfp, ci);
1560 }
1561 #endif
1562
1563 static VALUE
1564 vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1565 {
1566 VALUE val = vm_getivar(ci->recv, ci->me->def->body.attr.id, 0, ci, 1);
1567 cfp->sp -= 1;
1568 return val;
1569 }
1570
1571 static VALUE
1572 vm_call_attrset(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1573 {
1574 VALUE val = vm_setivar(ci->recv, ci->me->def->body.attr.id, *(cfp->sp - 1), 0, ci, 1);
1575 cfp->sp -= 2;
1576 return val;
1577 }
1578
1579 static inline VALUE
1580 vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv)
1581 {
1582 rb_proc_t *proc;
1583 VALUE val;
1584
1585 RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id);
1586 EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil);
1587
1588 /* control block frame */
1589 th->passed_me = ci->me;
1590 GetProcPtr(ci->me->def->body.proc, proc);
1591 val = vm_invoke_proc(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr);
1592
1593 EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, ci->recv, ci->me->called_id, ci->me->klass, val);
1594 RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->me->klass, ci->me->called_id);
1595
1596 return val;
1597 }
1598
1599 static VALUE
1600 vm_call_bmethod(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1601 {
1602 VALUE *argv = ALLOCA_N(VALUE, ci->argc);
1603 MEMCPY(argv, cfp->sp - ci->argc, VALUE, ci->argc);
1604 cfp->sp += - ci->argc - 1;
1605
1606 return vm_call_bmethod_body(th, ci, argv);
1607 }
1608
1609 static
1610 #ifdef _MSC_VER
1611 __forceinline
1612 #else
1613 inline
1614 #endif
1615 VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
1616
1617 static VALUE
1618 vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1619 {
1620 int i = ci->argc - 1;
1621 VALUE sym;
1622 rb_call_info_t ci_entry;
1623
1624 if (ci->argc == 0) {
1625 rb_raise(rb_eArgError, "no method name given");
1626 }
1627
1628 ci_entry = *ci; /* copy ci entry */
1629 ci = &ci_entry;
1630
1631 sym = TOPN(i);
1632
1633 if (SYMBOL_P(sym)) {
1634 ci->mid = SYM2ID(sym);
1635 }
1636 else if (!(ci->mid = rb_check_id(&sym))) {
1637 if (rb_method_basic_definition_p(CLASS_OF(ci->recv), idMethodMissing)) {
1638 VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i));
1639 rb_exc_raise(exc);
1640 }
1641 ci->mid = rb_to_id(sym);
1642 }
1643
1644 /* shift arguments */
1645 if (i > 0) {
1646 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
1647 }
1648 ci->me =
1649 rb_method_entry_without_refinements(CLASS_OF(ci->recv),
1650 ci->mid, &ci->defined_class);
1651 ci->argc -= 1;
1652 DEC_SP(1);
1653
1654 ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
1655
1656 return vm_call_method(th, reg_cfp, ci);
1657 }
1658
1659 static VALUE
1660 vm_call_opt_call(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1661 {
1662 rb_proc_t *proc;
1663 int argc = ci->argc;
1664 VALUE *argv = ALLOCA_N(VALUE, argc);
1665 GetProcPtr(ci->recv, proc);
1666 MEMCPY(argv, cfp->sp - argc, VALUE, argc);
1667 cfp->sp -= argc + 1;
1668
1669 return rb_vm_invoke_proc(th, proc, argc, argv, ci->blockptr);
1670 }
1671
1672 static VALUE
1673 vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1674 {
1675 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc);
1676 rb_call_info_t ci_entry;
1677
1678 ci_entry.flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
1679 ci_entry.argc = ci->argc+1;
1680 ci_entry.mid = idMethodMissing;
1681 ci_entry.blockptr = ci->blockptr;
1682 ci_entry.recv = ci->recv;
1683 ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class);
1684
1685 /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
1686 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
1687 if (ci->argc > 0) {
1688 MEMMOVE(argv+1, argv, VALUE, ci->argc);
1689 }
1690 argv[0] = ID2SYM(ci->mid);
1691 INC_SP(1);
1692
1693 th->method_missing_reason = ci->aux.missing_reason;
1694 return vm_call_method(th, reg_cfp, &ci_entry);
1695 }
1696
1697 static inline VALUE
1698 find_refinement(VALUE refinements, VALUE klass)
1699 {
1700 if (NIL_P(refinements)) {
1701 return Qnil;
1702 }
1703 return rb_hash_lookup(refinements, klass);
1704 }
1705
1706 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
1707 static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
1708
1709 static rb_control_frame_t *
1710 current_method_entry(rb_thread_t *th, rb_control_frame_t *cfp)
1711 {
1712 rb_control_frame_t *top_cfp = cfp;
1713
1714 if (cfp->iseq && cfp->iseq->type == ISEQ_TYPE_BLOCK) {
1715 rb_iseq_t *local_iseq = cfp->iseq->local_iseq;
1716 do {
1717 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1718 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
1719 /* TODO: orphan block */
1720 return top_cfp;
1721 }
1722 } while (cfp->iseq != local_iseq);
1723 }
1724 return cfp;
1725 }
1726
1727 static
1728 #ifdef _MSC_VER
1729 __forceinline
1730 #else
1731 inline
1732 #endif
1733 VALUE
1734 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
1735 {
1736 int enable_fastpath = 1;
1737 rb_call_info_t ci_temp;
1738
1739 start_method_dispatch:
1740 if (ci->me != 0) {
1741 if ((ci->me->flag == 0)) {
1742 normal_method_dispatch:
1743 switch (ci->me->def->type) {
1744 case VM_METHOD_TYPE_ISEQ:{
1745 CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath);
1746 return vm_call_iseq_setup(th, cfp, ci);
1747 }
1748 case VM_METHOD_TYPE_NOTIMPLEMENTED:
1749 case VM_METHOD_TYPE_CFUNC:
1750 CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath);
1751 return vm_call_cfunc(th, cfp, ci);
1752 case VM_METHOD_TYPE_ATTRSET:{
1753 rb_check_arity(ci->argc, 1, 1);
1754 ci->aux.index = 0;
1755 CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
1756 return vm_call_attrset(th, cfp, ci);
1757 }
1758 case VM_METHOD_TYPE_IVAR:{
1759 rb_check_arity(ci->argc, 0, 0);
1760 ci->aux.index = 0;
1761 CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
1762 return vm_call_ivar(th, cfp, ci);
1763 }
1764 case VM_METHOD_TYPE_MISSING:{
1765 ci->aux.missing_reason = 0;
1766 CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath);
1767 return vm_call_method_missing(th, cfp, ci);
1768 }
1769 case VM_METHOD_TYPE_BMETHOD:{
1770 CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath);
1771 return vm_call_bmethod(th, cfp, ci);
1772 }
1773 case VM_METHOD_TYPE_ZSUPER:{
1774 VALUE klass;
1775
1776 zsuper_method_dispatch:
1777 klass = RCLASS_SUPER(ci->me->klass);
1778 ci_temp = *ci;
1779 ci = &ci_temp;
1780
1781 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
1782
1783 if (ci->me != 0) {
1784 goto normal_method_dispatch;
1785 }
1786 else {
1787 goto start_method_dispatch;
1788 }
1789 }
1790 case VM_METHOD_TYPE_OPTIMIZED:{
1791 switch (ci->me->def->body.optimize_type) {
1792 case OPTIMIZED_METHOD_TYPE_SEND:
1793 CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath);
1794 return vm_call_opt_send(th, cfp, ci);
1795 case OPTIMIZED_METHOD_TYPE_CALL:
1796 CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath);
1797 return vm_call_opt_call(th, cfp, ci);
1798 default:
1799 rb_bug("vm_call_method: unsupported optimized method type (%d)",
1800 ci->me->def->body.optimize_type);
1801 }
1802 break;
1803 }
1804 case VM_METHOD_TYPE_UNDEF:
1805 break;
1806 case VM_METHOD_TYPE_REFINED:{
1807 NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep);
1808 VALUE refinements = cref ? cref->nd_refinements : Qnil;
1809 VALUE refinement, defined_class;
1810 rb_method_entry_t *me;
1811
1812 refinement = find_refinement(refinements,
1813 ci->defined_class);
1814 if (NIL_P(refinement)) {
1815 goto no_refinement_dispatch;
1816 }
1817 me = rb_method_entry(refinement, ci->mid, &defined_class);
1818 if (me) {
1819 if (ci->call == vm_call_super_method) {
1820 rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
1821 if (top_cfp->me &&
1822 rb_method_definition_eq(me->def, top_cfp->me->def)) {
1823 goto no_refinement_dispatch;
1824 }
1825 }
1826 ci->me = me;
1827 ci->defined_class = defined_class;
1828 if (me->def->type != VM_METHOD_TYPE_REFINED) {
1829 goto normal_method_dispatch;
1830 }
1831 }
1832
1833 no_refinement_dispatch:
1834 if (ci->me->def->body.orig_me) {
1835 ci->me = ci->me->def->body.orig_me;
1836 goto normal_method_dispatch;
1837 }
1838 else {
1839 goto zsuper_method_dispatch;
1840 }
1841 }
1842 }
1843 rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type);
1844 }
1845 else {
1846 int noex_safe;
1847 if (!(ci->flag & VM_CALL_FCALL) && (ci->me->flag & NOEX_MASK) & NOEX_PRIVATE) {
1848 int stat = NOEX_PRIVATE;
1849
1850 if (ci->flag & VM_CALL_VCALL) {
1851 stat |= NOEX_VCALL;
1852 }
1853 ci->aux.missing_reason = stat;
1854 CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
1855 return vm_call_method_missing(th, cfp, ci);
1856 }
1857 else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) {
1858 enable_fastpath = 0;
1859 if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) {
1860 ci->aux.missing_reason = NOEX_PROTECTED;
1861 return vm_call_method_missing(th, cfp, ci);
1862 }
1863 else {
1864 goto normal_method_dispatch;
1865 }
1866 }
1867 else if ((noex_safe = NOEX_SAFE(ci->me->flag)) > th->safe_level && (noex_safe > 2)) {
1868 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(ci->mid));
1869 }
1870 else {
1871 goto normal_method_dispatch;
1872 }
1873 }
1874 }
1875 else {
1876 /* method missing */
1877 int stat = 0;
1878 if (ci->flag & VM_CALL_VCALL) {
1879 stat |= NOEX_VCALL;
1880 }
1881 if (ci->flag & VM_CALL_SUPER) {
1882 stat |= NOEX_SUPER;
1883 }
1884 if (ci->mid == idMethodMissing) {
1885 rb_control_frame_t *reg_cfp = cfp;
1886 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc);
1887 rb_raise_method_missing(th, ci->argc, argv, ci->recv, stat);
1888 }
1889 else {
1890 ci->aux.missing_reason = stat;
1891 CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
1892 return vm_call_method_missing(th, cfp, ci);
1893 }
1894 }
1895
1896 rb_bug("vm_call_method: unreachable");
1897 }
1898
1899 static VALUE
1900 vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1901 {
1902 return vm_call_method(th, reg_cfp, ci);
1903 }
1904
1905 static VALUE
1906 vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1907 {
1908 return vm_call_method(th, reg_cfp, ci);
1909 }
1910
1911 /* super */
1912
1913 static inline VALUE
1914 vm_search_normal_superclass(VALUE klass)
1915 {
1916 if (BUILTIN_TYPE(klass) == T_ICLASS &&
1917 FL_TEST(RBASIC(klass)->klass, RMODULE_IS_REFINEMENT)) {
1918 klass = RBASIC(klass)->klass;
1919 }
1920 klass = RCLASS_ORIGIN(klass);
1921 return RCLASS_SUPER(klass);
1922 }
1923
1924 static void
1925 vm_super_outside(void)
1926 {
1927 rb_raise(rb_eNoMethodError, "super called outside of method");
1928 }
1929
1930 static int
1931 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci)
1932 {
1933 while (iseq && !iseq->klass) {
1934 iseq = iseq->parent_iseq;
1935 }
1936
1937 if (iseq == 0) {
1938 return -1;
1939 }
1940
1941 ci->mid = iseq->defined_method_id;
1942
1943 if (iseq != iseq->local_iseq) {
1944 /* defined by Module#define_method() */
1945 rb_control_frame_t *lcfp = GET_CFP();
1946
1947 if (!sigval) {
1948 /* zsuper */
1949 return -2;
1950 }
1951
1952 while (lcfp->iseq != iseq) {
1953 rb_thread_t *th = GET_THREAD();
1954 VALUE *tep = VM_EP_PREV_EP(lcfp->ep);
1955 while (1) {
1956 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
1957 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) {
1958 return -1;
1959 }
1960 if (lcfp->ep == tep) {
1961 break;
1962 }
1963 }
1964 }
1965
1966 /* temporary measure for [Bug #2420] [Bug #3136] */
1967 if (!lcfp->me) {
1968 return -1;
1969 }
1970
1971 ci->mid = lcfp->me->def->original_id;
1972 ci->klass = vm_search_normal_superclass(lcfp->klass);
1973 }
1974 else {
1975 ci->klass = vm_search_normal_superclass(reg_cfp->klass);
1976 }
1977
1978 return 0;
1979 }
1980
1981 static void
1982 vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
1983 {
1984 VALUE current_defined_class;
1985 rb_iseq_t *iseq = GET_ISEQ();
1986 VALUE sigval = TOPN(ci->orig_argc);
1987
1988 current_defined_class = GET_CFP()->klass;
1989 if (NIL_P(current_defined_class)) {
1990 vm_super_outside();
1991 }
1992
1993 if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) {
1994 current_defined_class = RCLASS_REFINED_CLASS(current_defined_class);
1995 }
1996
1997 if (!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) &&
1998 !rb_obj_is_kind_of(ci->recv, current_defined_class)) {
1999 VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
2000 RBASIC(current_defined_class)->klass : current_defined_class;
2001
2002 rb_raise(rb_eTypeError,
2003 "self has wrong type to call super in this context: "
2004 "%s (expected %s)",
2005 rb_obj_classname(ci->recv), rb_class2name(m));
2006 }
2007
2008 switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) {
2009 case -1:
2010 vm_super_outside();
2011 case -2:
2012 rb_raise(rb_eRuntimeError,
2013 "implicit argument passing of super from method defined"
2014 " by define_method() is not supported."
2015 " Specify all arguments explicitly.");
2016 }
2017
2018 /* TODO: use inline cache */
2019 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
2020 ci->call = vm_call_super_method;
2021
2022 while (iseq && !iseq->klass) {
2023 iseq = iseq->parent_iseq;
2024 }
2025
2026 if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) {
2027 ci->klass = RCLASS_SUPER(ci->defined_class);
2028 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
2029 }
2030 }
2031
2032 /* yield */
2033
2034 static inline int
2035 block_proc_is_lambda(const VALUE procval)
2036 {
2037 rb_proc_t *proc;
2038
2039 if (procval) {
2040 GetProcPtr(procval, proc);
2041 return proc->is_lambda;
2042 }
2043 else {
2044 return 0;
2045 }
2046 }
2047
2048 static inline VALUE
2049 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
2050 VALUE self, int argc, const VALUE *argv,
2051 const rb_block_t *blockargptr)
2052 {
2053 NODE *ifunc = (NODE *) block->iseq;
2054 VALUE val, arg, blockarg;
2055 int lambda = block_proc_is_lambda(block->proc);
2056
2057 if (lambda) {
2058 arg = rb_ary_new4(argc, argv);
2059 }
2060 else if (argc == 0) {
2061 arg = Qnil;
2062 }
2063 else {
2064 arg = argv[0];
2065 }
2066
2067 if (blockargptr) {
2068 if (blockargptr->proc) {
2069 blockarg = blockargptr->proc;
2070 }
2071 else {
2072 blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc);
2073 }
2074 }
2075 else {
2076 blockarg = Qnil;
2077 }
2078
2079 vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self,
2080 0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
2081 th->cfp->sp, 1, 0);
2082
2083 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
2084
2085 th->cfp++;
2086 return val;
2087 }
2088
2089
2090 /*--
2091 * @brief on supplied all of optional, rest and post parameters.
2092 * @pre iseq is block style (not lambda style)
2093 */
2094 static inline int
2095 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq,
2096 int argc, VALUE *argv)
2097 {
2098 rb_num_t opt_pc = 0;
2099 int i;
2100 const int m = iseq->argc;
2101 const int r = iseq->arg_rest;
2102 int len = iseq->arg_post_len;
2103 int start = iseq->arg_post_start;
2104 int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */
2105 int psize = rsize > len ? len : rsize; /* # of post arguments */
2106 int osize = 0; /* # of opt arguments */
2107 VALUE ary;
2108
2109 /* reserves arguments for post parameters */
2110 rsize -= psize;
2111
2112 if (iseq->arg_opts) {
2113 const int opts = iseq->arg_opts - 1;
2114 if (rsize > opts) {
2115 osize = opts;
2116 opt_pc = iseq->arg_opt_table[opts];
2117 }
2118 else {
2119 osize = rsize;
2120 opt_pc = iseq->arg_opt_table[rsize];
2121 }
2122 }
2123 rsize -= osize;
2124
2125 if (0) {
2126 printf(" argc: %d\n", argc);
2127 printf(" len: %d\n", len);
2128 printf("start: %d\n", start);
2129 printf("rsize: %d\n", rsize);
2130 }
2131
2132 if (r == -1) {
2133 /* copy post argument */
2134 MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize);
2135 }
2136 else {
2137 ary = rb_ary_new4(rsize, &argv[r]);
2138
2139 /* copy post argument */
2140 MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize);
2141 argv[r] = ary;
2142 }
2143
2144 for (i=psize; i<len; i++) {
2145 argv[start + i] = Qnil;
2146 }
2147
2148 return (int)opt_pc;
2149 }
2150
2151 static inline int
2152 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq,
2153 int orig_argc, VALUE *argv,
2154 const rb_block_t *blockptr)
2155 {
2156 int i;
2157 int argc = orig_argc;
2158 const int m = iseq->argc;
2159 VALUE ary, arg0;
2160 VALUE keyword_hash = Qnil;
2161 int opt_pc = 0;
2162
2163 th->mark_stack_len = argc;
2164
2165 /*
2166 * yield [1, 2]
2167 * => {|a|} => a = [1, 2]
2168 * => {|a, b|} => a, b = [1, 2]
2169 */
2170 arg0 = argv[0];
2171 if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */
2172 ((m + iseq->arg_post_len) > 0 || /* positional arguments exist */
2173 iseq->arg_opts > 2 || /* multiple optional arguments exist */
2174 iseq->arg_keyword != -1 || /* any keyword arguments */
2175 0) &&
2176 argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */
2177 th->mark_stack_len = argc = RARRAY_LENINT(ary);
2178
2179 CHECK_VM_STACK_OVERFLOW(th->cfp, argc);
2180
2181 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc);
2182 }
2183 else {
2184 /* vm_push_frame current argv is at the top of sp because vm_invoke_block
2185 * set sp at the first element of argv.
2186 * Therefore when rb_check_array_type(arg0) called to_ary and called to_ary
2187 * or method_missing run vm_push_frame, it initializes local variables.
2188 * see also https://bugs.ruby-lang.org/issues/8484
2189 */
2190 argv[0] = arg0;
2191 }
2192
2193 /* keyword argument */
2194 if (iseq->arg_keyword != -1) {
2195 argc = vm_callee_setup_keyword_arg(iseq, argc, m, argv, &keyword_hash);
2196 }
2197
2198 for (i=argc; i<m; i++) {
2199 argv[i] = Qnil;
2200 }
2201
2202 if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
2203 const int arg_size = iseq->arg_size;
2204 if (arg_size < argc) {
2205 /*
2206 * yield 1, 2
2207 * => {|a|} # truncate
2208 */
2209 th->mark_stack_len = argc = arg_size;
2210 }
2211 }
2212 else {
2213 int r = iseq->arg_rest;
2214
2215 if (iseq->arg_post_len ||
2216 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
2217 opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv);
2218 }
2219 else {
2220 if (argc < r) {
2221 /* yield 1
2222 * => {|a, b, *r|}
2223 */
2224 for (i=argc; i<r; i++) {
2225 argv[i] = Qnil;
2226 }
2227 argv[r] = rb_ary_new();
2228 }
2229 else {
2230 argv[r] = rb_ary_new4(argc-r, &argv[r]);
2231 }
2232 }
2233
2234 th->mark_stack_len = iseq->arg_size;
2235 }
2236
2237 /* keyword argument */
2238 if (iseq->arg_keyword != -1) {
2239 argv[iseq->arg_keyword] = keyword_hash;
2240 }
2241
2242 /* {|&b|} */
2243 if (iseq->arg_block != -1) {
2244 VALUE procval = Qnil;
2245
2246 if (blockptr) {
2247 if (blockptr->proc == 0) {
2248 procval = rb_vm_make_proc(th, blockptr, rb_cProc);
2249 }
2250 else {
2251 procval = blockptr->proc;
2252 }
2253 }
2254
2255 argv[iseq->arg_block] = procval;
2256 }
2257
2258 th->mark_stack_len = 0;
2259 return opt_pc;
2260 }
2261
2262 static inline int
2263 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
2264 int argc, VALUE *argv, const rb_block_t *blockptr, int lambda)
2265 {
2266 if (0) { /* for debug */
2267 printf(" argc: %d\n", argc);
2268 printf("iseq argc: %d\n", iseq->argc);
2269 printf("iseq opts: %d\n", iseq->arg_opts);
2270 printf("iseq rest: %d\n", iseq->arg_rest);
2271 printf("iseq post: %d\n", iseq->arg_post_len);
2272 printf("iseq blck: %d\n", iseq->arg_block);
2273 printf("iseq smpl: %d\n", iseq->arg_simple);
2274 printf(" lambda: %s\n", lambda ? "true" : "false");
2275 }
2276
2277 if (lambda) {
2278 /* call as method */
2279 rb_call_info_t ci_entry;
2280 ci_entry.flag = 0;
2281 ci_entry.argc = argc;
2282 ci_entry.blockptr = (rb_block_t *)blockptr;
2283 VM_CALLEE_SETUP_ARG(th, &ci_entry, iseq, argv, 1);
2284 return ci_entry.aux.opt_pc;
2285 }
2286 else {
2287 return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr);
2288 }
2289 }
2290
2291 static VALUE
2292 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
2293 {
2294 const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp);
2295 rb_iseq_t *iseq;
2296 VALUE type = GET_ISEQ()->local_iseq->type;
2297
2298 if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
2299 rb_vm_localjump_error("no block given (yield)", Qnil, 0);
2300 }
2301 iseq = block->iseq;
2302
2303 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) {
2304 vm_caller_setup_args(th, GET_CFP(), ci);
2305 }
2306
2307 if (BUILTIN_TYPE(iseq) != T_NODE) {
2308 int opt_pc;
2309 const int arg_size = iseq->arg_size;
2310 VALUE * const rsp = GET_SP() - ci->argc;
2311 SET_SP(rsp);
2312
2313 CHECK_VM_STACK_OVERFLOW(GET_CFP(), iseq->stack_max);
2314 opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, block_proc_is_lambda(block->proc));
2315
2316 vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self,
2317 block->klass,
2318 VM_ENVVAL_PREV_EP_PTR(block->ep),
2319 iseq->iseq_encoded + opt_pc,
2320 rsp + arg_size,
2321 iseq->local_size - arg_size, 0);
2322
2323 return Qundef;
2324 }
2325 else {
2326 VALUE val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0);
2327 POPN(ci->argc); /* TODO: should put before C/yield? */
2328 return val;
2329 }
2330 }
2331