* process.c (rb_spawn_internal): new function to specify
[ruby-svn.git] / vm_insnhelper.c
blobc411cf287a53af6b1d943a596c80cb751b80799c
1 /**********************************************************************
3 insnhelper.c - instruction helper functions.
5 $Author$
7 Copyright (C) 2007 Koichi Sasada
9 **********************************************************************/
11 /* finish iseq array */
12 #include "insns.inc"
14 #include <math.h>
16 /* control stack frame */
19 #ifndef INLINE
20 #define INLINE inline
21 #endif
23 static inline rb_control_frame_t *
24 vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE type,
25 VALUE self, VALUE specval, VALUE *pc,
26 VALUE *sp, VALUE *lfp, int local_size)
28 VALUE *dfp;
29 rb_control_frame_t *cfp;
30 int i;
32 /* nil initialize */
33 for (i=0; i < local_size; i++) {
34 *sp = Qnil;
35 sp++;
38 /* set special val */
39 *sp = GC_GUARDED_PTR(specval);
40 dfp = sp;
42 if (lfp == 0) {
43 lfp = sp;
46 cfp = th->cfp = th->cfp - 1;
47 cfp->pc = pc;
48 cfp->sp = sp + 1;
49 cfp->bp = sp + 1;
50 cfp->iseq = iseq;
51 cfp->flag = type;
52 cfp->self = self;
53 cfp->lfp = lfp;
54 cfp->dfp = dfp;
55 cfp->proc = 0;
57 #define COLLECT_PROFILE 0
58 #if COLLECT_PROFILE
59 cfp->prof_time_self = clock();
60 cfp->prof_time_chld = 0;
61 #endif
63 if (VMDEBUG == 2) {
64 SDR();
67 return cfp;
70 static inline void
71 vm_pop_frame(rb_thread_t *th)
73 #if COLLECT_PROFILE
74 rb_control_frame_t *cfp = th->cfp;
76 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
77 VALUE current_time = clock();
78 rb_control_frame_t *cfp = th->cfp;
79 cfp->prof_time_self = current_time - cfp->prof_time_self;
80 (cfp+1)->prof_time_chld += cfp->prof_time_self;
82 cfp->iseq->profile.count++;
83 cfp->iseq->profile.time_cumu = cfp->prof_time_self;
84 cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld;
86 else if (0 /* c method? */) {
89 #endif
90 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
92 if (VMDEBUG == 2) {
93 SDR();
97 /* method dispatch */
99 static int
100 vm_callee_setup_arg(rb_thread_t *th, rb_iseq_t *iseq,
101 int argc, VALUE *argv, rb_block_t **block)
103 const int m = iseq->argc;
104 const int orig_argc = argc;
106 if (LIKELY(iseq->arg_simple & 0x01)) {
107 /* simple check */
108 if (argc != m) {
109 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
110 argc, m);
112 return 0;
114 else {
115 VALUE * const dst = argv;
116 int opt_pc = 0;
117 th->mark_stack_len = argc + iseq->arg_size;
119 /* mandatory */
120 if (argc < (m + iseq->arg_post_len)) { /* check with post arg */
121 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
122 argc, m + iseq->arg_post_len);
125 argv += m;
126 argc -= m;
128 /* post arguments */
129 if (iseq->arg_post_len) {
130 if (!(orig_argc < iseq->arg_post_start)) {
131 VALUE *new_argv = ALLOCA_N(VALUE, argc);
132 MEMCPY(new_argv, argv, VALUE, argc);
133 argv = new_argv;
136 MEMCPY(&dst[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len],
137 VALUE, iseq->arg_post_len);
140 /* opt arguments */
141 if (iseq->arg_opts) {
142 const int opts = iseq->arg_opts - 1 /* no opt */;
144 if (iseq->arg_rest == -1 && argc > opts) {
145 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
146 orig_argc, m + opts + iseq->arg_post_len);
149 if (argc > opts) {
150 argc -= opts;
151 argv += opts;
152 opt_pc = iseq->arg_opt_table[opts]; /* no opt */
154 else {
155 int i;
156 for (i = argc; i<opts; i++) {
157 dst[i + m] = Qnil;
159 opt_pc = iseq->arg_opt_table[argc];
160 argc = 0;
164 /* rest arguments */
165 if (iseq->arg_rest != -1) {
166 dst[iseq->arg_rest] = rb_ary_new4(argc, argv);
167 argc = 0;
170 /* block arguments */
171 if (block && iseq->arg_block != -1) {
172 VALUE blockval = Qnil;
173 rb_block_t * const blockptr = *block;
175 if (argc != 0) {
176 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
177 orig_argc, m + iseq->arg_post_len);
180 if (blockptr) {
181 /* make Proc object */
182 if (blockptr->proc == 0) {
183 rb_proc_t *proc;
185 blockval = vm_make_proc(th, th->cfp, blockptr);
187 GetProcPtr(blockval, proc);
188 *block = &proc->block;
190 else {
191 blockval = blockptr->proc;
195 dst[iseq->arg_block] = blockval; /* Proc or nil */
198 th->mark_stack_len = 0;
199 return opt_pc;
203 static inline int
204 caller_setup_args(rb_thread_t *th, rb_control_frame_t *cfp, VALUE flag,
205 int argc, rb_iseq_t *blockiseq, rb_block_t **block)
207 rb_block_t *blockptr = 0;
209 if (block) {
210 if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
211 rb_proc_t *po;
212 VALUE proc;
214 proc = *(--cfp->sp);
216 if (proc != Qnil) {
217 if (!rb_obj_is_proc(proc)) {
218 VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
219 if (NIL_P(b)) {
220 rb_raise(rb_eTypeError,
221 "wrong argument type %s (expected Proc)",
222 rb_obj_classname(proc));
224 proc = b;
226 GetProcPtr(proc, po);
227 blockptr = &po->block;
228 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
229 *block = blockptr;
232 else if (blockiseq) {
233 blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
234 blockptr->iseq = blockiseq;
235 blockptr->proc = 0;
236 *block = blockptr;
240 /* expand top of stack? */
241 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
242 VALUE ary = *(cfp->sp - 1);
243 VALUE *ptr;
244 int i;
245 VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
247 if (NIL_P(tmp)) {
248 /* do nothing */
250 else {
251 int len = RARRAY_LEN(tmp);
252 ptr = RARRAY_PTR(tmp);
253 cfp->sp -= 1;
255 CHECK_STACK_OVERFLOW(cfp, len);
257 for (i = 0; i < len; i++) {
258 *cfp->sp++ = ptr[i];
260 argc += i-1;
264 return argc;
267 static inline VALUE
268 call_cfunc(VALUE (*func)(), VALUE recv, int len, int argc, const VALUE *argv)
270 /* printf("len: %d, argc: %d\n", len, argc); */
272 if (len >= 0 && argc != len) {
273 rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
274 argc, len);
277 switch (len) {
278 case -2:
279 return (*func) (recv, rb_ary_new4(argc, argv));
280 break;
281 case -1:
282 return (*func) (argc, argv, recv);
283 break;
284 case 0:
285 return (*func) (recv);
286 break;
287 case 1:
288 return (*func) (recv, argv[0]);
289 break;
290 case 2:
291 return (*func) (recv, argv[0], argv[1]);
292 break;
293 case 3:
294 return (*func) (recv, argv[0], argv[1], argv[2]);
295 break;
296 case 4:
297 return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
298 break;
299 case 5:
300 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
301 break;
302 case 6:
303 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
304 argv[5]);
305 break;
306 case 7:
307 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
308 argv[5], argv[6]);
309 break;
310 case 8:
311 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
312 argv[5], argv[6], argv[7]);
313 break;
314 case 9:
315 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
316 argv[5], argv[6], argv[7], argv[8]);
317 break;
318 case 10:
319 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
320 argv[5], argv[6], argv[7], argv[8], argv[9]);
321 break;
322 case 11:
323 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
324 argv[5], argv[6], argv[7], argv[8], argv[9],
325 argv[10]);
326 break;
327 case 12:
328 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
329 argv[5], argv[6], argv[7], argv[8], argv[9],
330 argv[10], argv[11]);
331 break;
332 case 13:
333 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
334 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
335 argv[11], argv[12]);
336 break;
337 case 14:
338 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
339 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
340 argv[11], argv[12], argv[13]);
341 break;
342 case 15:
343 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
344 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
345 argv[11], argv[12], argv[13], argv[14]);
346 break;
347 default:
348 rb_raise(rb_eArgError, "too many arguments(%d)", len);
349 break;
351 return Qnil; /* not reached */
354 static inline VALUE
355 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, int num,
356 ID id, VALUE recv, VALUE klass, VALUE flag,
357 NODE *mn, rb_block_t *blockptr)
359 VALUE val;
361 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
363 rb_control_frame_t *cfp =
364 vm_push_frame(th, 0, FRAME_MAGIC_CFUNC | (flag << FRAME_MAGIC_MASK_BITS),
365 recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
367 cfp->method_id = id;
368 cfp->method_class = klass;
370 reg_cfp->sp -= num + 1;
372 val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);
374 if (reg_cfp != th->cfp + 1) {
375 rb_bug("cfp consistency error - send");
377 vm_pop_frame(th);
379 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
381 return val;
384 static int
385 vm_cfunc_flags(rb_control_frame_t *cfp)
387 if (RUBYVM_CFUNC_FRAME_P(cfp))
388 return cfp->flag >> FRAME_MAGIC_MASK_BITS;
389 return 0;
392 static inline VALUE
393 vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv,
394 VALUE klass, int argc, VALUE *argv, rb_block_t *blockptr)
396 rb_control_frame_t *cfp = th->cfp;
397 rb_proc_t *proc;
398 VALUE val;
400 /* control block frame */
401 (cfp-2)->method_id = id;
402 (cfp-2)->method_class = klass;
404 GetProcPtr(procval, proc);
405 val = vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
406 return val;
409 static inline VALUE
410 vm_method_missing(rb_thread_t *th, ID id, VALUE recv, int num,
411 rb_block_t *blockptr, int opt)
413 rb_control_frame_t *reg_cfp = th->cfp;
414 VALUE *argv = STACK_ADDR_FROM_TOP(num + 1);
415 VALUE val;
416 argv[0] = ID2SYM(id);
417 th->method_missing_reason = opt;
418 th->passed_block = blockptr;
419 val = rb_funcall2(recv, idMethodMissing, num + 1, argv);
420 POPN(num + 1);
421 return val;
424 static inline void
425 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
426 int argc, rb_block_t *blockptr, VALUE flag,
427 VALUE iseqval, VALUE recv, VALUE klass)
429 rb_iseq_t *iseq;
430 int opt_pc, i;
431 VALUE *sp, *rsp = cfp->sp - argc;
433 /* TODO: eliminate it */
434 GetISeqPtr(iseqval, iseq);
435 opt_pc = vm_callee_setup_arg(th, iseq, argc, rsp, &blockptr);
437 /* stack overflow check */
438 CHECK_STACK_OVERFLOW(cfp, iseq->stack_max);
440 sp = rsp + iseq->arg_size;
442 if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) {
443 if (0) printf("local_size: %d, arg_size: %d\n",
444 iseq->local_size, iseq->arg_size);
446 /* clear local variables */
447 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
448 *sp++ = Qnil;
451 vm_push_frame(th, iseq,
452 FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
453 iseq->iseq_encoded + opt_pc, sp, 0, 0);
455 cfp->sp = rsp - 1 /* recv */;
457 else {
458 VALUE *p_rsp;
459 cfp = ++th->cfp; /* pop cf */
460 p_rsp = th->cfp->sp;
462 /* copy arguments */
463 for (i=0; i < (sp - rsp); i++) {
464 p_rsp[i] = rsp[i];
467 sp -= rsp - p_rsp;
469 /* clear local variables */
470 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
471 *sp++ = Qnil;
474 vm_push_frame(th, iseq,
475 FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
476 iseq->iseq_encoded + opt_pc, sp, 0, 0);
480 static inline VALUE
481 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
482 int num, rb_block_t *blockptr, VALUE flag,
483 ID id, NODE *mn, VALUE recv, VALUE klass)
485 VALUE val;
487 start_method_dispatch:
489 if ((mn != 0)) {
490 if ((mn->nd_noex == 0)) {
491 /* dispatch method */
492 NODE *node;
494 normal_method_dispatch:
496 node = mn->nd_body;
498 switch (nd_type(node)) {
499 case RUBY_VM_METHOD_NODE:{
500 vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv, klass);
501 return Qundef;
503 case NODE_CFUNC:{
504 val = vm_call_cfunc(th, cfp, num, id, recv, mn->nd_clss, flag, node, blockptr);
505 break;
507 case NODE_ATTRSET:{
508 val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1));
509 cfp->sp -= 2;
510 break;
512 case NODE_IVAR:{
513 if (num != 0) {
514 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
515 num);
517 val = rb_attr_get(recv, node->nd_vid);
518 cfp->sp -= 1;
519 break;
521 case NODE_BMETHOD:{
522 VALUE *argv = cfp->sp - num;
523 val = vm_call_bmethod(th, id, node->nd_cval, recv, klass, num, argv, blockptr);
524 cfp->sp += - num - 1;
525 break;
527 case NODE_ZSUPER:{
528 klass = RCLASS_SUPER(mn->nd_clss);
529 mn = rb_method_node(klass, id);
531 if (mn != 0) {
532 goto normal_method_dispatch;
534 else {
535 goto start_method_dispatch;
538 default:{
539 printf("node: %s\n", ruby_node_name(nd_type(node)));
540 rb_bug("eval_invoke_method: unreachable");
541 /* unreachable */
542 break;
546 else {
547 int noex_safe;
549 if (!(flag & VM_CALL_FCALL_BIT) &&
550 (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
551 int stat = NOEX_PRIVATE;
553 if (flag & VM_CALL_VCALL_BIT) {
554 stat |= NOEX_VCALL;
556 val = vm_method_missing(th, id, recv, num, blockptr, stat);
558 else if (((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) &&
559 !(flag & VM_CALL_SEND_BIT)) {
560 VALUE defined_class = mn->nd_clss;
562 if (TYPE(defined_class) == T_ICLASS) {
563 defined_class = RBASIC(defined_class)->klass;
566 if (!rb_obj_is_kind_of(cfp->self, rb_class_real(defined_class))) {
567 val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED);
569 else {
570 goto normal_method_dispatch;
573 else if ((noex_safe = NOEX_SAFE(mn->nd_noex)) > th->safe_level &&
574 (noex_safe > 2)) {
575 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id));
577 else {
578 goto normal_method_dispatch;
582 else {
583 /* method missing */
584 if (id == idMethodMissing) {
585 rb_bug("method missing");
587 else {
588 int stat = 0;
589 if (flag & VM_CALL_VCALL_BIT) {
590 stat |= NOEX_VCALL;
592 if (flag & VM_CALL_SUPER_BIT) {
593 stat |= NOEX_SUPER;
595 val = vm_method_missing(th, id, recv, num, blockptr, stat);
599 RUBY_VM_CHECK_INTS();
600 return val;
603 static inline void
604 vm_send_optimize(rb_control_frame_t *reg_cfp,
605 NODE **mn, rb_num_t *flag, rb_num_t *num, ID *id, VALUE klass)
607 if (*mn && nd_type((*mn)->nd_body) == NODE_CFUNC) {
608 NODE *node = (*mn)->nd_body;
609 extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
611 if (node->nd_cfnc == rb_f_send) {
612 int i = *num - 1;
613 VALUE sym = TOPN(i);
614 *id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
616 /* shift arguments */
617 if (i > 0) {
618 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
621 *mn = rb_method_node(klass, *id);
622 *num -= 1;
623 DEC_SP(1);
624 *flag |= VM_CALL_FCALL_BIT;
629 /* yield */
631 static inline int
632 block_proc_is_lambda(VALUE procval)
634 rb_proc_t *proc;
636 if (procval) {
637 GetProcPtr(procval, proc);
638 return proc->is_lambda;
640 else {
641 return 0;
645 static inline VALUE
646 vm_yield_with_cfunc(rb_thread_t *th, rb_block_t *block,
647 VALUE self, int argc, VALUE *argv)
649 NODE *ifunc = (NODE *) block->iseq;
650 VALUE val;
651 VALUE arg;
652 int lambda = block_proc_is_lambda(block->proc);
654 if (lambda) {
655 arg = rb_ary_new4(argc, argv);
657 else if (argc == 0) {
658 arg = Qnil;
660 else {
661 arg = argv[0];
664 vm_push_frame(th, 0, FRAME_MAGIC_IFUNC,
665 self, (VALUE)block->dfp,
666 0, th->cfp->sp, block->lfp, 1);
668 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv);
670 th->cfp++;
671 return val;
674 static inline int
675 vm_yield_setup_args(rb_thread_t *th, rb_iseq_t *iseq,
676 int argc, VALUE *argv, rb_block_t *blockptr, int lambda)
678 if (0) { /* for debug */
679 printf(" argc: %d\n", argc);
680 printf("iseq argc: %d\n", iseq->argc);
681 printf("iseq opts: %d\n", iseq->arg_opts);
682 printf("iseq rest: %d\n", iseq->arg_rest);
683 printf("iseq post: %d\n", iseq->arg_post_len);
684 printf("iseq blck: %d\n", iseq->arg_block);
685 printf("iseq smpl: %d\n", iseq->arg_simple);
686 printf(" lambda: %s\n", lambda ? "true" : "false");
689 if (lambda) {
690 /* call as method */
691 return vm_callee_setup_arg(th, iseq, argc, argv, &blockptr);
693 else {
694 int i;
695 const int m = iseq->argc;
697 th->mark_stack_len = argc;
700 * yield [1, 2]
701 * => {|a|} => a = [1, 2]
702 * => {|a, b|} => a, b = [1, 2]
704 if (!(iseq->arg_simple & 0x02) &&
705 (m + iseq->arg_post_len) > 0 &&
706 argc == 1 && TYPE(argv[0]) == T_ARRAY) {
707 VALUE ary = argv[0];
708 th->mark_stack_len = argc = RARRAY_LEN(ary);
710 CHECK_STACK_OVERFLOW(th->cfp, argc);
712 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc);
715 for (i=argc; i<m; i++) {
716 argv[i] = Qnil;
719 if (iseq->arg_rest == -1) {
720 if (m < argc) {
722 * yield 1, 2
723 * => {|a|} # truncate
725 th->mark_stack_len = argc = m;
728 else {
729 int r = iseq->arg_rest;
731 if (iseq->arg_post_len) {
732 int len = iseq->arg_post_len;
733 int start = iseq->arg_post_start;
734 int rsize = argc > m ? argc - m : 0;
735 int psize = rsize;
736 VALUE ary;
738 if (psize > len) psize = len;
740 ary = rb_ary_new4(rsize - psize, &argv[r]);
742 if (0) {
743 printf(" argc: %d\n", argc);
744 printf(" len: %d\n", len);
745 printf("start: %d\n", start);
746 printf("rsize: %d\n", rsize);
749 /* copy post argument */
750 MEMMOVE(&argv[start], &argv[r + rsize - psize], VALUE, psize);
752 for (i=psize; i<len; i++) {
753 argv[start + i] = Qnil;
755 argv[r] = ary;
757 else {
758 if (argc < r) {
759 /* yield 1
760 * => {|a, b, *r|}
762 for (i=argc; i<r; i++) {
763 argv[i] = Qnil;
765 argv[r] = rb_ary_new();
767 else {
768 argv[r] = rb_ary_new4(argc-r, &argv[r]);
772 th->mark_stack_len = iseq->arg_size;
775 /* {|&b|} */
776 if (iseq->arg_block != -1) {
777 VALUE procval = Qnil;
779 if (blockptr) {
780 procval = blockptr->proc;
783 argv[iseq->arg_block] = procval;
786 th->mark_stack_len = 0;
787 return 0;
791 static VALUE
792 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag)
794 VALUE val;
795 rb_block_t *block = GET_BLOCK_PTR();
796 rb_iseq_t *iseq;
797 int argc = num;
799 if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) {
800 vm_localjump_error("no block given (yield)", Qnil, 0);
802 iseq = block->iseq;
804 argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0);
806 if (BUILTIN_TYPE(iseq) != T_NODE) {
807 int opt_pc;
808 const int arg_size = iseq->arg_size;
809 VALUE *rsp = GET_SP() - argc;
810 SET_SP(rsp);
812 CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max);
813 opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0,
814 block_proc_is_lambda(block->proc));
816 vm_push_frame(th, iseq,
817 FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
818 iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
819 iseq->local_size - arg_size);
821 return Qundef;
823 else {
824 val = vm_yield_with_cfunc(th, block, block->self, argc, STACK_ADDR_FROM_TOP(argc));
825 POPN(argc); /* TODO: should put before C/yield? */
826 return val;
830 /* cref */
832 static NODE *
833 lfp_get_special_cref(VALUE *lfp)
835 struct RValues *values;
836 if (((VALUE)(values = (void *)lfp[-1])) != Qnil && values->basic.klass) {
837 return (NODE *)values->basic.klass;
839 else {
840 return 0;
844 static struct RValues *
845 new_value(void)
847 struct RValues *val = RVALUES(rb_newobj());
848 OBJSETUP(val, 0, T_VALUES);
849 val->v1 = val->v2 = val->v3 = Qnil;
850 return val;
853 static struct RValues *
854 lfp_svar_place(rb_thread_t *th, VALUE *lfp)
856 struct RValues *svar;
858 if (th->local_lfp != lfp) {
859 svar = (struct RValues *)lfp[-1];
860 if ((VALUE)svar == Qnil) {
861 svar = new_value();
862 lfp[-1] = (VALUE)svar;
865 else {
866 svar = (struct RValues *)th->local_svar;
867 if ((VALUE)svar == Qnil) {
868 svar = new_value();
869 th->local_svar = (VALUE)svar;
872 return svar;
875 static VALUE
876 lfp_svar_get(rb_thread_t *th, VALUE *lfp, VALUE key)
878 struct RValues *svar = lfp_svar_place(th, lfp);
880 switch (key) {
881 case 0:
882 return svar->v1;
883 case 1:
884 return svar->v2;
885 case 2:
886 return svar->basic.klass;
887 default: {
888 VALUE hash = svar->v3;
890 if (hash == Qnil) {
891 return Qnil;
893 else {
894 return rb_hash_lookup(hash, key);
900 static void
901 lfp_svar_set(rb_thread_t *th, VALUE *lfp, VALUE key, VALUE val)
903 struct RValues *svar = lfp_svar_place(th, lfp);
905 switch (key) {
906 case 0:
907 svar->v1 = val;
908 return;
909 case 1:
910 svar->v2 = val;
911 return;
912 case 2:
913 svar->basic.klass = val;
914 return;
915 default: {
916 VALUE hash = svar->v3;
918 if (hash == Qnil) {
919 svar->v3 = hash = rb_hash_new();
921 rb_hash_aset(hash, key, val);
926 static NODE *
927 get_cref(rb_iseq_t *iseq, VALUE *lfp)
929 NODE *cref;
930 if ((cref = lfp_get_special_cref(lfp)) != 0) {
931 /* */
933 else if ((cref = iseq->cref_stack) != 0) {
934 /* */
936 else {
937 rb_bug("get_cref: unreachable");
939 return cref;
942 static inline VALUE
943 vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type)
945 VALUE val;
947 if (type == 0) {
948 if (FIXNUM_P(key)) key = FIX2INT(key);
949 val = lfp_svar_get(th, lfp, key);
951 else {
952 VALUE backref = lfp_svar_get(th, lfp, 1);
954 if (type & 0x01) {
955 switch (type >> 1) {
956 case '&':
957 val = rb_reg_last_match(backref);
958 break;
959 case '`':
960 val = rb_reg_match_pre(backref);
961 break;
962 case '\'':
963 val = rb_reg_match_post(backref);
964 break;
965 case '+':
966 val = rb_reg_match_last(backref);
967 break;
968 default:
969 rb_bug("unexpected back-ref");
972 else {
973 val = rb_reg_nth_match(type >> 1, backref);
976 return val;
979 static inline void
980 vm_check_if_namespace(VALUE klass)
982 switch (TYPE(klass)) {
983 case T_CLASS:
984 case T_MODULE:
985 break;
986 default:
987 rb_raise(rb_eTypeError, "%s is not a class/module",
988 RSTRING_PTR(rb_obj_as_string(klass)));
992 static inline VALUE
993 vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
994 VALUE klass, ID id, int is_defined)
996 VALUE val;
998 if (klass == Qnil) {
999 /* in current lexical scope */
1000 NODE *root_cref = get_cref(iseq, th->cfp->lfp);
1001 NODE *cref = root_cref;
1003 while (cref && cref->nd_next) {
1004 klass = cref->nd_clss;
1005 cref = cref->nd_next;
1007 if (klass == 0) {
1008 continue;
1010 if (NIL_P(klass)) {
1011 if (is_defined) {
1012 /* TODO: check */
1013 return 1;
1015 else {
1016 klass = CLASS_OF(th->cfp->self);
1017 return rb_const_get(klass, id);
1020 search_continue:
1021 if (RCLASS_IV_TBL(klass) &&
1022 st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
1023 if (val == Qundef) {
1024 rb_autoload_load(klass, id);
1025 goto search_continue;
1027 else {
1028 if (is_defined) {
1029 return 1;
1031 else {
1032 return val;
1037 klass = root_cref->nd_clss;
1038 if (is_defined) {
1039 return rb_const_defined(klass, id);
1041 else {
1042 return rb_const_get(klass, id);
1045 else {
1046 vm_check_if_namespace(klass);
1047 if (is_defined) {
1048 return rb_const_defined_from(klass, id);
1050 else {
1051 return rb_const_get_from(klass, id);
1056 static inline VALUE
1057 vm_get_cvar_base(rb_thread_t *th, rb_iseq_t *iseq)
1059 NODE *cref = get_cref(iseq, th->cfp->lfp);
1060 VALUE klass = Qnil;
1062 if (cref) {
1063 klass = cref->nd_clss;
1064 if (!cref->nd_next) {
1065 rb_warn("class variable access from toplevel");
1068 if (NIL_P(klass)) {
1069 rb_raise(rb_eTypeError, "no class variables available");
1071 return klass;
1074 static inline void
1075 vm_define_method(rb_thread_t *th, VALUE obj,
1076 ID id, rb_iseq_t *miseq, rb_num_t is_singleton, NODE *cref)
1078 NODE *newbody;
1079 int noex = cref->nd_visi;
1080 VALUE klass = cref->nd_clss;
1082 if (is_singleton) {
1083 if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
1084 rb_raise(rb_eTypeError,
1085 "can't define singleton method \"%s\" for %s",
1086 rb_id2name(id), rb_obj_classname(obj));
1089 if (OBJ_FROZEN(obj)) {
1090 rb_error_frozen("object");
1093 klass = rb_singleton_class(obj);
1094 noex = NOEX_PUBLIC;
1097 /* dup */
1098 COPY_CREF(miseq->cref_stack, cref);
1099 miseq->klass = klass;
1100 miseq->defined_method_id = id;
1101 newbody = NEW_NODE(RUBY_VM_METHOD_NODE, 0, miseq->self, 0);
1102 rb_add_method(klass, id, newbody, noex);
1104 if (!is_singleton && noex == NOEX_MODFUNC) {
1105 rb_add_method(rb_singleton_class(klass), id, newbody, NOEX_PUBLIC);
1107 INC_VM_STATE_VERSION();
1110 static inline NODE *
1111 vm_method_search(VALUE id, VALUE klass, IC ic)
1113 NODE *mn;
1115 #if OPT_INLINE_METHOD_CACHE
1117 if (LIKELY(klass == ic->ic_class) &&
1118 LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
1119 mn = ic->ic_method;
1121 else {
1122 mn = rb_method_node(klass, id);
1123 ic->ic_class = klass;
1124 ic->ic_method = mn;
1125 ic->ic_vmstat = GET_VM_STATE_VERSION();
1128 #else
1129 mn = rb_method_node(klass, id);
1130 #endif
1131 return mn;
1134 static inline VALUE
1135 vm_search_normal_superclass(VALUE klass, VALUE recv)
1137 if (BUILTIN_TYPE(klass) == T_CLASS) {
1138 klass = RCLASS_SUPER(klass);
1140 else if (BUILTIN_TYPE(klass) == T_MODULE) {
1141 VALUE k = CLASS_OF(recv);
1142 while (k) {
1143 if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) {
1144 klass = RCLASS_SUPER(k);
1145 break;
1147 k = RCLASS_SUPER(k);
1150 return klass;
1153 static void
1154 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip, VALUE recv, VALUE sigval, ID *idp, VALUE *klassp)
1156 ID id;
1157 VALUE klass;
1159 while (ip && !ip->klass) {
1160 ip = ip->parent_iseq;
1163 if (ip == 0) {
1164 rb_raise(rb_eNoMethodError, "super called outside of method");
1167 id = ip->defined_method_id;
1169 if (ip != ip->local_iseq) {
1170 /* defined by Module#define_method() */
1171 rb_control_frame_t *lcfp = GET_CFP();
1173 while (lcfp->iseq != ip) {
1174 VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
1175 while (1) {
1176 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
1177 if (lcfp->dfp == tdfp) {
1178 break;
1183 id = lcfp->method_id;
1184 klass = vm_search_normal_superclass(lcfp->method_class, recv);
1186 if (sigval == Qfalse) {
1187 /* zsuper */
1188 rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.");
1191 else {
1192 klass = vm_search_normal_superclass(ip->klass, recv);
1195 *idp = id;
1196 *klassp = klass;
1199 static VALUE
1200 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj)
1202 rb_num_t state = throw_state & 0xff;
1203 rb_num_t flag = throw_state & 0x8000;
1204 rb_num_t level = throw_state >> 16;
1206 if (state != 0) {
1207 VALUE *pt;
1208 int i;
1209 if (flag != 0) {
1210 if (throw_state & 0x4000) {
1211 pt = (void *)1;
1213 else {
1214 pt = 0;
1217 else {
1218 if (state == TAG_BREAK) {
1219 rb_control_frame_t *cfp = GET_CFP();
1220 VALUE *dfp = GET_DFP();
1221 int is_orphan = 1;
1222 rb_iseq_t *base_iseq = GET_ISEQ();
1224 search_parent:
1225 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
1226 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
1227 base_iseq = base_iseq->parent_iseq;
1229 while ((VALUE *) cfp < th->stack + th->stack_size) {
1230 if (cfp->dfp == dfp) {
1231 goto search_parent;
1233 cfp++;
1235 rb_bug("VM (throw): can't find break base.");
1238 if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) {
1239 /* lambda{... break ...} */
1240 is_orphan = 0;
1241 pt = dfp;
1243 else {
1244 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
1246 while ((VALUE *)cfp < th->stack + th->stack_size) {
1247 if (cfp->dfp == dfp) {
1248 VALUE epc = epc = cfp->pc - cfp->iseq->iseq_encoded;
1249 rb_iseq_t *iseq = cfp->iseq;
1250 int i;
1252 for (i=0; i<iseq->catch_table_size; i++) {
1253 struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
1255 if (entry->type == CATCH_TYPE_BREAK &&
1256 entry->start < epc && entry->end >= epc) {
1257 if (entry->cont == epc) {
1258 goto found;
1260 else {
1261 break;
1265 break;
1267 found:
1268 pt = dfp;
1269 is_orphan = 0;
1270 break;
1272 cfp++;
1276 if (is_orphan) {
1277 vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
1280 else if (state == TAG_RETRY) {
1281 pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
1282 for (i = 0; i < level; i++) {
1283 pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
1286 else if (state == TAG_RETURN) {
1287 rb_control_frame_t *cfp = GET_CFP();
1288 VALUE *dfp = GET_DFP();
1289 int is_orphan = 1;
1292 * check orphan:
1294 while ((VALUE *) cfp < th->stack + th->stack_size) {
1295 if (GET_DFP() == dfp) {
1296 if (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_LAMBDA) {
1297 /* in lambda */
1298 is_orphan = 0;
1299 break;
1302 if (GET_LFP() == cfp->lfp &&
1303 cfp->iseq->type == ISEQ_TYPE_METHOD) {
1304 is_orphan = 0;
1305 break;
1307 cfp++;
1310 if (is_orphan) {
1311 vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
1314 pt = GET_LFP();
1316 else {
1317 rb_bug("isns(throw): unsupport throw type");
1320 th->state = state;
1321 return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
1323 else {
1324 /* continue throw */
1325 VALUE err = throwobj;
1327 if (FIXNUM_P(err)) {
1328 th->state = FIX2INT(err);
1330 else if (SYMBOL_P(err)) {
1331 th->state = TAG_THROW;
1333 else if (BUILTIN_TYPE(err) == T_NODE) {
1334 th->state = GET_THROWOBJ_STATE(err);
1336 else {
1337 th->state = TAG_RAISE;
1338 /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
1340 return err;
1344 static inline void
1345 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, int num, int flag)
1347 int is_splat = flag & 0x01;
1348 int space_size = num + is_splat;
1349 VALUE *base = cfp->sp, *ptr;
1350 volatile VALUE tmp_ary;
1351 int len;
1353 if (TYPE(ary) != T_ARRAY) {
1354 ary = rb_ary_to_ary(ary);
1357 cfp->sp += space_size;
1359 tmp_ary = ary;
1360 ptr = RARRAY_PTR(ary);
1361 len = RARRAY_LEN(ary);
1363 if (flag & 0x02) {
1364 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
1365 int i = 0, j;
1367 if (len < num) {
1368 for (i=0; i<num-len; i++) {
1369 *base++ = Qnil;
1372 for (j=0; i<num; i++, j++) {
1373 VALUE v = ptr[len - j - 1];
1374 *base++ = v;
1376 if (is_splat) {
1377 *base = rb_ary_new4(len - j, ptr);
1380 else {
1381 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
1382 int i;
1383 VALUE *bptr = &base[space_size - 1];
1385 for (i=0; i<num; i++) {
1386 if (len <= i) {
1387 for (; i<num; i++) {
1388 *bptr-- = Qnil;
1390 break;
1392 *bptr-- = ptr[i];
1394 if (is_splat) {
1395 if (num > len) {
1396 *bptr = rb_ary_new();
1398 else {
1399 *bptr = rb_ary_new4(len - num, ptr + num);
1405 static inline int
1406 check_cfunc(NODE *mn, void *func)
1408 if (mn && nd_type(mn->nd_body) == NODE_CFUNC &&
1409 mn->nd_body->nd_cfnc == func) {
1410 return 1;
1412 else {
1413 return 0;
1417 static VALUE
1418 opt_eq_func(VALUE recv, VALUE obj, IC ic)
1420 VALUE val = Qundef;
1422 if (FIXNUM_2_P(recv, obj) &&
1423 BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
1424 long a = FIX2LONG(recv), b = FIX2LONG(obj);
1426 if (a == b) {
1427 val = Qtrue;
1429 else {
1430 val = Qfalse;
1433 else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
1434 if (HEAP_CLASS_OF(recv) == rb_cFloat &&
1435 HEAP_CLASS_OF(obj) == rb_cFloat &&
1436 BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
1437 double a = RFLOAT_VALUE(recv);
1438 double b = RFLOAT_VALUE(obj);
1440 if (isnan(a) || isnan(b)) {
1441 val = Qfalse;
1443 else if (a == b) {
1444 val = Qtrue;
1446 else {
1447 val = Qfalse;
1450 else if (HEAP_CLASS_OF(recv) == rb_cString &&
1451 HEAP_CLASS_OF(obj) == rb_cString &&
1452 BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
1453 val = rb_str_equal(recv, obj);
1455 else {
1456 NODE *mn = vm_method_search(idEq, CLASS_OF(recv), ic);
1457 extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
1459 if (check_cfunc(mn, rb_obj_equal)) {
1460 return recv == obj ? Qtrue : Qfalse;
1465 return val;