* lib/open3.rb (Open3.popen3w): removed.
[ruby-svn.git] / compile.c
blobc4cbf837e1f15f1138ffa60a6d958edec748518f
1 /**********************************************************************
3 compile.c - ruby node tree -> VM instruction sequence
5 $Author$
6 created at: 04/01/01 03:42:15 JST
8 Copyright (C) 2004-2007 Koichi Sasada
10 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include "ruby/node.h"
15 #define USE_INSN_STACK_INCREASE 1
16 #include "vm_core.h"
17 #include "compile.h"
18 #include "insns.inc"
19 #include "insns_info.inc"
21 #ifdef HAVE_STDARG_PROTOTYPES
22 #include <stdarg.h>
23 #define va_init_list(a,b) va_start(a,b)
24 #else
25 #include <varargs.h>
26 #define va_init_list(a,b) va_start(a)
27 #endif
29 /* iseq.c */
30 VALUE iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt);
32 /* vm.c */
33 VALUE vm_eval(void *);
35 /* types */
37 typedef struct iseq_link_element {
38 enum {
39 ISEQ_ELEMENT_NONE = INT2FIX(0x00),
40 ISEQ_ELEMENT_LABEL = INT2FIX(0x01),
41 ISEQ_ELEMENT_INSN = INT2FIX(0x02),
42 ISEQ_ELEMENT_ADJUST = INT2FIX(0x03),
43 } type;
44 struct iseq_link_element *next;
45 struct iseq_link_element *prev;
46 } LINK_ELEMENT;
48 typedef struct iseq_link_anchor {
49 LINK_ELEMENT anchor;
50 LINK_ELEMENT *last;
51 } LINK_ANCHOR;
53 typedef struct iseq_label_data {
54 LINK_ELEMENT link;
55 int label_no;
56 int position;
57 int sc_state;
58 int set;
59 int sp;
60 } LABEL;
62 typedef struct iseq_insn_data {
63 LINK_ELEMENT link;
64 enum ruby_vminsn_type insn_id;
65 int line_no;
66 int operand_size;
67 int sc_state;
68 VALUE *operands;
69 } INSN;
71 typedef struct iseq_adjust_data {
72 LINK_ELEMENT link;
73 LABEL *label;
74 int line_no;
75 } ADJUST;
77 struct ensure_range {
78 LABEL *begin;
79 LABEL *end;
80 struct ensure_range *next;
83 struct iseq_compile_data_ensure_node_stack {
84 NODE *ensure_node;
85 struct iseq_compile_data_ensure_node_stack *prev;
86 struct ensure_range *erange;
89 #include "optinsn.inc"
90 #if OPT_INSTRUCTIONS_UNIFICATION
91 #include "optunifs.inc"
92 #endif
94 /* for debug */
95 #if CPDEBUG < 0
96 #define ISEQ_ARG iseq,
97 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
98 #else
99 #define ISEQ_ARG
100 #define ISEQ_ARG_DECLARE
101 #endif
103 #if CPDEBUG
104 #define gl_node_level iseq->compile_data->node_level
105 #if 0
106 static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor);
107 #endif
108 #endif
110 static void dump_disasm_list(LINK_ELEMENT *elem);
112 static int insn_data_length(INSN *iobj);
113 static int insn_data_line_no(INSN *iobj);
114 static int calc_sp_depth(int depth, INSN *iobj);
116 static void ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem);
118 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...);
119 static LABEL *new_label_body(rb_iseq_t *iseq, int line);
120 static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
122 static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int);
123 static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
124 static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
125 static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
127 static int iseq_set_local_table(rb_iseq_t *iseq, ID *tbl);
128 static int iseq_set_exception_local_table(rb_iseq_t *iseq);
129 static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node);
131 static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
132 static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
133 static int iseq_set_exception_table(rb_iseq_t *iseq);
134 static int iseq_set_optargs_table(rb_iseq_t *iseq);
137 * To make Array to LinkedList, use link_anchor
140 static void
141 verify_list(ISEQ_ARG_DECLARE char *info, LINK_ANCHOR *anchor)
143 #if CPDEBUG
144 int flag = 0;
145 LINK_ELEMENT *list, *plist;
147 if (!compile_debug) return;
149 list = anchor->anchor.next;
150 plist = &anchor->anchor;
151 while (list) {
152 if (plist != list->prev) {
153 flag += 1;
155 plist = list;
156 list = list->next;
159 if (anchor->last != plist && anchor->last != 0) {
160 flag |= 0x70000;
163 if (flag != 0) {
164 rb_bug("list verify error: %08x (%s)", flag, info);
166 #endif
168 #if CPDEBUG < 0
169 #define verify_list(info, anchor) verify_list(iseq, info, anchor)
170 #endif
173 * elem1, elem2 => elem1, elem2, elem
175 static void
176 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
178 elem->prev = anchor->last;
179 anchor->last->next = elem;
180 anchor->last = elem;
181 verify_list("add", anchor);
183 #if CPDEBUG < 0
184 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, anchor, elem)
185 #endif
187 static int
188 iseq_add_mark_object(rb_iseq_t *iseq, VALUE v)
190 if (!SPECIAL_CONST_P(v)) {
191 rb_ary_push(iseq->mark_ary, v);
193 return COMPILE_OK;
196 #define ruby_sourcefile RSTRING_PTR(iseq->filename)
198 static int
199 iseq_add_mark_object_compile_time(rb_iseq_t *iseq, VALUE v)
201 if (!SPECIAL_CONST_P(v)) {
202 rb_ary_push(iseq->compile_data->mark_ary, v);
204 return COMPILE_OK;
207 VALUE
208 iseq_compile(VALUE self, NODE *node)
210 DECL_ANCHOR(ret);
211 rb_iseq_t *iseq;
212 INIT_ANCHOR(ret);
213 GetISeqPtr(self, iseq);
215 if (node == 0) {
216 COMPILE(ret, "nil", node);
217 iseq_set_local_table(iseq, 0);
219 else if (nd_type(node) == NODE_SCOPE) {
220 /* iseq type of top, method, class, block */
221 iseq_set_local_table(iseq, node->nd_tbl);
222 iseq_set_arguments(iseq, ret, node->nd_args);
224 switch (iseq->type) {
225 case ISEQ_TYPE_BLOCK: {
226 LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
227 LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
229 ADD_LABEL(ret, start);
230 COMPILE(ret, "block body", node->nd_body);
231 ADD_LABEL(ret, end);
233 /* wide range catch handler must put at last */
234 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
235 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
236 break;
238 case ISEQ_TYPE_CLASS: {
239 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CLASS);
240 COMPILE(ret, "scoped node", node->nd_body);
241 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
242 break;
244 case ISEQ_TYPE_METHOD: {
245 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CALL);
246 COMPILE(ret, "scoped node", node->nd_body);
247 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
248 break;
250 default: {
251 COMPILE(ret, "scoped node", node->nd_body);
252 break;
256 else {
257 switch (iseq->type) {
258 case ISEQ_TYPE_METHOD:
259 case ISEQ_TYPE_CLASS:
260 case ISEQ_TYPE_BLOCK:
261 case ISEQ_TYPE_EVAL:
262 case ISEQ_TYPE_TOP:
263 rb_compile_error(ERROR_ARGS "compile/should not be reached: %s:%d",
264 __FILE__, __LINE__);
265 break;
266 case ISEQ_TYPE_RESCUE:
267 iseq_set_exception_local_table(iseq);
268 COMPILE(ret, "rescue", node);
269 break;
270 case ISEQ_TYPE_ENSURE:
271 iseq_set_exception_local_table(iseq);
272 COMPILE_POPED(ret, "ensure", node);
273 break;
274 case ISEQ_TYPE_DEFINED_GUARD:
275 COMPILE(ret, "defined guard", node);
276 break;
277 default:
278 rb_bug("unknown scope");
282 if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) {
283 ADD_INSN2(ret, 0, getdynamic, INT2FIX(1), INT2FIX(0));
284 ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
286 else {
287 ADD_INSN(ret, iseq->compile_data->last_line, leave);
290 return iseq_setup(iseq, ret);
294 iseq_translate_threaded_code(rb_iseq_t *iseq)
296 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
298 #if OPT_DIRECT_THREADED_CODE
299 const void *const *table = (const void **)vm_eval(0);
300 #else
301 extern const void *const *get_insns_address_table();
302 const void *const *table = get_insns_address_table();
303 #endif
304 int i;
306 iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size);
307 MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size);
309 for (i = 0; i < iseq->iseq_size; /* */ ) {
310 int insn = iseq->iseq_encoded[i];
311 int len = insn_len(insn);
312 iseq->iseq_encoded[i] = (VALUE)table[insn];
313 i += len;
315 #else
316 iseq->iseq_encoded = iseq->iseq;
317 #endif
318 return COMPILE_OK;
321 /*********************************************/
322 /* definition of data structure for compiler */
323 /*********************************************/
325 static void *
326 compile_data_alloc(rb_iseq_t *iseq, size_t size)
328 void *ptr = 0;
329 struct iseq_compile_data_storage *storage =
330 iseq->compile_data->storage_current;
332 if (storage->pos + size > storage->size) {
333 unsigned long alloc_size = storage->size * 2;
335 retry:
336 if (alloc_size < size) {
337 alloc_size *= 2;
338 goto retry;
340 storage->next = (void *)ALLOC_N(char, alloc_size +
341 sizeof(struct
342 iseq_compile_data_storage));
343 storage = iseq->compile_data->storage_current = storage->next;
344 storage->next = 0;
345 storage->pos = 0;
346 storage->size = alloc_size;
347 storage->buff = (char *)(&storage->buff + 1);
350 ptr = (void *)&storage->buff[storage->pos];
351 storage->pos += size;
352 return ptr;
355 static INSN *
356 compile_data_alloc_insn(rb_iseq_t *iseq)
358 return (INSN *)compile_data_alloc(iseq, sizeof(INSN));
361 static LABEL *
362 compile_data_alloc_label(rb_iseq_t *iseq)
364 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
367 static ADJUST *
368 compile_data_alloc_adjust(rb_iseq_t *iseq)
370 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
374 * elem1, elemX => elem1, elem2, elemX
376 static void
377 INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
379 elem2->next = elem1->next;
380 elem2->prev = elem1;
381 elem1->next = elem2;
382 if (elem2->next) {
383 elem2->next->prev = elem2;
387 #if 0 /* unused */
389 * elemX, elem1 => elemX, elem2, elem1
391 static void
392 INSERT_ELEM_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
394 elem2->prev = elem1->prev;
395 elem2->next = elem1;
396 elem1->prev = elem2;
397 if (elem2->prev) {
398 elem2->prev->next = elem2;
401 #endif
404 * elemX, elem1, elemY => elemX, elem2, elemY
406 static void
407 REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
409 elem2->prev = elem1->prev;
410 elem2->next = elem1->next;
411 if (elem1->prev) {
412 elem1->prev->next = elem2;
414 if (elem1->next) {
415 elem1->next->prev = elem2;
419 static void
420 REMOVE_ELEM(LINK_ELEMENT *elem)
422 elem->prev->next = elem->next;
423 if (elem->next) {
424 elem->next->prev = elem->prev;
428 static LINK_ELEMENT *
429 FIRST_ELEMENT(LINK_ANCHOR *anchor)
431 return anchor->anchor.next;
434 #if 0 /* unused */
435 static LINK_ELEMENT *
436 LAST_ELEMENT(LINK_ANCHOR *anchor)
438 return anchor->last;
440 #endif
442 static LINK_ELEMENT *
443 POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
445 LINK_ELEMENT *elem = anchor->last;
446 anchor->last = anchor->last->prev;
447 anchor->last->next = 0;
448 verify_list("pop", anchor);
449 return elem;
451 #if CPDEBUG < 0
452 #define POP_ELEMENT(anchor) POP_ELEMENT(iseq, anchor)
453 #endif
455 #if 0 /* unused */
456 static LINK_ELEMENT *
457 SHIFT_ELEMENT(LINK_ANCHOR *anchor)
459 LINK_ELEMENT *elem = anchor->anchor.next;
460 if (elem) {
461 anchor->anchor.next = elem->next;
463 return elem;
465 #endif
467 #if 0 /* unused */
468 static int
469 LIST_SIZE(LINK_ANCHOR *anchor)
471 LINK_ELEMENT *elem = anchor->anchor.next;
472 int size = 0;
473 while (elem) {
474 size += 1;
475 elem = elem->next;
477 return size;
479 #endif
481 static int
482 LIST_SIZE_ZERO(LINK_ANCHOR *anchor)
484 if (anchor->anchor.next == 0) {
485 return 1;
487 else {
488 return 0;
493 * anc1: e1, e2, e3
494 * anc2: e4, e5
495 *#=>
496 * anc1: e1, e2, e3, e4, e5
497 * anc2: e4, e5 (broken)
499 static void
500 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
502 if (anc2->anchor.next) {
503 anc1->last->next = anc2->anchor.next;
504 anc2->anchor.next->prev = anc1->last;
505 anc1->last = anc2->last;
507 verify_list("append", anc1);
509 #if CPDEBUG < 0
510 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, anc1, anc2)
511 #endif
514 * anc1: e1, e2, e3
515 * anc2: e4, e5
516 *#=>
517 * anc1: e4, e5, e1, e2, e3
518 * anc2: e4, e5 (broken)
520 static void
521 INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
523 if (anc2->anchor.next) {
524 LINK_ELEMENT *first = anc1->anchor.next;
525 anc1->anchor.next = anc2->anchor.next;
526 anc1->anchor.next->prev = &anc1->anchor;
527 anc2->last->next = first;
528 if (first) {
529 first->prev = anc2->last;
531 else {
532 anc1->last = anc2->last;
536 verify_list("append", anc1);
538 #if CPDEBUG < 0
539 #define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, anc1, anc2)
540 #endif
542 #if 0 /* unused */
544 * anc1: e1, e2, e3
545 * anc2: e4, e5
546 *#=>
547 * anc1: e4, e5
548 * anc2: e1, e2, e3
550 static void
551 SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
553 LINK_ANCHOR tmp = *anc2;
555 /* it has bug */
556 *anc2 = *anc1;
557 *anc1 = tmp;
559 verify_list("swap1", anc1);
560 verify_list("swap2", anc2);
562 #if CPDEBUG < 0
563 #define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, anc1, anc2)
564 #endif
566 static LINK_ANCHOR *
567 REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc)
569 LINK_ELEMENT *first, *last, *elem, *e;
570 first = &anc->anchor;
571 elem = first->next;
572 last = anc->last;
574 if (elem != 0) {
575 anc->anchor.next = last;
576 anc->last = elem;
578 else {
579 /* null list */
580 return anc;
582 while (elem) {
583 e = elem->next;
584 elem->next = elem->prev;
585 elem->prev = e;
586 elem = e;
589 first->next = last;
590 last->prev = first;
591 anc->last->next = 0;
593 verify_list("reverse", anc);
594 return anc;
596 #if CPDEBUG < 0
597 #define REVERSE_LIST(anc) REVERSE_LIST(iseq, anc)
598 #endif
599 #endif
601 #if CPDEBUG && 0
602 static void
603 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
605 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
606 printf("----\n");
607 printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
608 anchor->anchor.next, anchor->last);
609 while (list) {
610 printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
611 list->prev, FIX2INT(list->type));
612 list = list->next;
614 printf("----\n");
616 dump_disasm_list(anchor->anchor.next);
617 verify_list("debug list", anchor);
619 #if CPDEBUG < 0
620 #define debug_list(anc) debug_list(iseq, anc)
621 #endif
622 #endif
624 static LABEL *
625 new_label_body(rb_iseq_t *iseq, int line)
627 LABEL *labelobj = compile_data_alloc_label(iseq);
629 labelobj->link.type = ISEQ_ELEMENT_LABEL;
630 labelobj->link.next = 0;
632 labelobj->label_no = iseq->compile_data->label_no++;
633 labelobj->sc_state = 0;
634 labelobj->sp = -1;
635 return labelobj;
638 static ADJUST *
639 new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
641 ADJUST *adjust = compile_data_alloc_adjust(iseq);
642 adjust->link.type = ISEQ_ELEMENT_ADJUST;
643 adjust->link.next = 0;
644 adjust->label = label;
645 adjust->line_no = line;
646 return adjust;
649 static INSN *
650 new_insn_core(rb_iseq_t *iseq, int line_no,
651 int insn_id, int argc, VALUE *argv)
653 INSN *iobj = compile_data_alloc_insn(iseq);
655 iobj->link.type = ISEQ_ELEMENT_INSN;
656 iobj->link.next = 0;
657 iobj->insn_id = insn_id;
658 iobj->line_no = line_no;
659 iobj->operands = argv;
660 iobj->operand_size = argc;
661 iobj->sc_state = 0;
662 return iobj;
665 static INSN *
666 new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...)
668 VALUE *operands = 0;
669 va_list argv;
670 if (argc > 0) {
671 int i;
672 va_init_list(argv, argc);
673 operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
674 for (i = 0; i < argc; i++) {
675 VALUE v = va_arg(argv, VALUE);
676 operands[i] = v;
678 va_end(argv);
680 return new_insn_core(iseq, line_no, insn_id, argc, operands);
683 static INSN *
684 new_insn_send(rb_iseq_t *iseq, int line_no,
685 VALUE id, VALUE argc, VALUE block, VALUE flag)
687 INSN *iobj = 0;
688 VALUE *operands =
689 (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 5);
690 operands[0] = id;
691 operands[1] = argc;
692 operands[2] = block;
693 operands[3] = flag;
694 operands[4] = 0;
695 iobj = new_insn_core(iseq, line_no, BIN(send), 5, operands);
696 return iobj;
699 static VALUE
700 new_child_iseq(rb_iseq_t *iseq, NODE *node,
701 VALUE name, VALUE parent, VALUE type)
703 VALUE ret;
705 debugs("[new_child_iseq]> ---------------------------------------\n");
706 ret = rb_iseq_new_with_opt(node, name, iseq_filename(iseq->self),
707 parent, type, iseq->compile_data->option);
708 debugs("[new_child_iseq]< ---------------------------------------\n");
709 iseq_add_mark_object(iseq, ret);
710 return ret;
713 static int
714 iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
716 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
718 if (compile_debug > 5)
719 dump_disasm_list(FIRST_ELEMENT(anchor));
721 debugs("[compile step 3.1 (iseq_optimize)]\n");
722 iseq_optimize(iseq, anchor);
724 if (compile_debug > 5)
725 dump_disasm_list(FIRST_ELEMENT(anchor));
727 if (iseq->compile_data->option->instructions_unification) {
728 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
729 iseq_insns_unification(iseq, anchor);
730 if (compile_debug > 5)
731 dump_disasm_list(FIRST_ELEMENT(anchor));
734 if (iseq->compile_data->option->stack_caching) {
735 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
736 iseq_set_sequence_stackcaching(iseq, anchor);
737 if (compile_debug > 5)
738 dump_disasm_list(FIRST_ELEMENT(anchor));
741 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
742 iseq_set_sequence(iseq, anchor);
743 if (compile_debug > 5)
744 dump_disasm_list(FIRST_ELEMENT(anchor));
746 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
747 iseq_set_exception_table(iseq);
749 debugs("[compile step 4.3 (set_optargs_table)] \n");
750 iseq_set_optargs_table(iseq);
752 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
753 iseq_translate_threaded_code(iseq);
755 if (compile_debug > 1) {
756 VALUE str = ruby_iseq_disasm(iseq->self);
757 printf("%s\n", StringValueCStr(str));
758 fflush(stdout);
760 debugs("[compile step: finish]\n");
762 return 0;
765 static int
766 iseq_set_exception_local_table(rb_iseq_t *iseq)
768 static ID id_dollar_bang;
770 if (!id_dollar_bang) {
771 id_dollar_bang = rb_intern("#$!");
773 iseq->local_table = (ID *)ALLOC_N(ID *, 1);
774 iseq->local_table_size = iseq->local_size = 1;
775 iseq->local_table[0] = id_dollar_bang;
776 return COMPILE_OK;
779 static int
780 get_dyna_var_idx_at_raw(rb_iseq_t *iseq, ID id)
782 int i;
784 for (i = 0; i < iseq->local_table_size; i++) {
785 if (iseq->local_table[i] == id) {
786 return i;
789 return -1;
792 static int
793 get_local_var_idx(rb_iseq_t *iseq, ID id)
795 int idx = get_dyna_var_idx_at_raw(iseq->local_iseq, id);
797 if (idx < 0) {
798 rb_bug("get_local_var_idx: %d", idx);
801 return idx;
804 static int
805 get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls)
807 int lv = 0, idx = -1;
809 while (iseq) {
810 idx = get_dyna_var_idx_at_raw(iseq, id);
811 if (idx >= 0) {
812 break;
814 iseq = iseq->parent_iseq;
815 lv++;
818 if (idx < 0) {
819 rb_bug("get_dyna_var_idx: -1");
822 *level = lv;
823 *ls = iseq->local_size;
824 return idx;
827 static int
828 iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
830 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
832 if (node_args) {
833 NODE *node_aux = node_args->nd_next;
834 NODE *node_opt = node_args->nd_opt;
835 ID rest_id = 0;
836 int last_comma = 0;
837 ID block_id = 0;
838 NODE *node_init = 0;
840 if (nd_type(node_args) != NODE_ARGS) {
841 rb_bug("iseq_set_arguments: NODE_ARGS is expected, but %s",
842 ruby_node_name(nd_type(node_args)));
846 * new argument infromation:
847 * NODE_ARGS [m: int, o: NODE_OPT_ARG, ->]
848 * NODE_ARGS_AUX [r: ID, b: ID, ->]
849 * NODE_ARGS_AUX [Pst: id, Plen: int, init: NODE*]
850 * optarg information:
851 * NODE_OPT_ARGS [idx, expr, next ->]
852 * init arg:
853 * NODE_AND(m_init, p_init)
854 * if "r" is 1, it's means "{|x,|}" type block parameter.
857 iseq->argc = node_args->nd_frml;
858 debugs(" - argc: %d\n", iseq->argc);
860 if (node_aux) {
861 rest_id = node_aux->nd_rest;
862 if (rest_id == 1) {
863 last_comma = 1;
864 rest_id = 0;
866 block_id = (ID)node_aux->nd_body;
867 node_aux = node_aux->nd_next;
869 if (node_aux) {
870 ID post_start_id = node_aux->nd_pid;
871 iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, post_start_id);
872 iseq->arg_post_len = node_aux->nd_plen;
873 node_init = node_aux->nd_next;
877 if (node_opt) {
878 NODE *node = node_opt;
879 LABEL *label;
880 VALUE labels = rb_ary_new();
881 int i = 0, j;
883 while (node) {
884 label = NEW_LABEL(nd_line(node));
885 rb_ary_push(labels, (VALUE)label | 1);
886 ADD_LABEL(optargs, label);
887 COMPILE_POPED(optargs, "optarg", node->nd_body);
888 node = node->nd_next;
889 i += 1;
892 /* last label */
893 label = NEW_LABEL(nd_line(node_args));
894 rb_ary_push(labels, (VALUE)label | 1);
895 ADD_LABEL(optargs, label);
896 i += 1;
898 iseq->arg_opts = i;
899 iseq->arg_opt_table = ALLOC_N(VALUE, i);
900 MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i);
901 for (j = 0; j < i; j++) {
902 iseq->arg_opt_table[j] &= ~1;
905 else {
906 iseq->arg_opts = 0;
909 if (node_init) {
910 if (node_init->nd_1st) { /* m_init */
911 COMPILE_POPED(optargs, "init arguments (m)", node_init->nd_1st);
913 if (node_init->nd_2nd) { /* p_init */
914 COMPILE_POPED(optargs, "init arguments (p)", node_init->nd_2nd);
918 if (rest_id) {
919 iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id);
921 if (iseq->arg_rest == -1) {
922 rb_bug("arg_rest: -1");
925 if (iseq->arg_post_start == 0) {
926 iseq->arg_post_start = iseq->arg_rest + 1;
930 if (block_id) {
931 iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id);
934 if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 ||
935 iseq->arg_rest != -1 || iseq->arg_block != -1) {
936 iseq->arg_simple = 0;
938 /* set arg_size: size of arguments */
939 if (iseq->arg_block != -1) {
940 iseq->arg_size = iseq->arg_block + 1;
942 else if (iseq->arg_post_len) {
943 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
945 else if (iseq->arg_rest != -1) {
946 iseq->arg_size = iseq->arg_rest + 1;
948 else if (iseq->arg_opts) {
949 iseq->arg_size = iseq->argc + iseq->arg_opts - 1;
951 else {
952 iseq->arg_size = iseq->argc;
955 else {
956 iseq->arg_simple = 1;
957 iseq->arg_size = iseq->argc;
960 if (iseq->type == ISEQ_TYPE_BLOCK) {
961 if (iseq->arg_opts == 0 && iseq->arg_post_len == 0 && iseq->arg_rest == -1) {
962 if (iseq->argc == 1 && last_comma == 0) {
963 /* {|a|} */
964 iseq->arg_simple |= 0x02;
969 else {
970 iseq->arg_simple = 1;
973 return COMPILE_OK;
976 static int
977 iseq_set_local_table(rb_iseq_t *iseq, ID *tbl)
979 int size;
981 if (tbl) {
982 size = *tbl;
983 tbl++;
985 else {
986 size = 0;
989 if (size > 0) {
990 iseq->local_table = (ID *)ALLOC_N(ID *, size);
991 MEMCPY(iseq->local_table, tbl, ID *, size);
994 iseq->local_size = iseq->local_table_size = size;
996 if (iseq->type == ISEQ_TYPE_METHOD ||
997 iseq->type == ISEQ_TYPE_CLASS ||
998 iseq->type == ISEQ_TYPE_TOP) {
999 iseq->local_size += 1 /* svar */;
1002 debugs("iseq_set_local_table: %d, %d\n", iseq->local_size, iseq->local_table_size);
1003 return COMPILE_OK;
1007 ruby insn object array -> raw instruction sequence
1009 static int
1010 iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1012 LABEL *lobj;
1013 INSN *iobj;
1014 struct iseq_insn_info_entry *insn_info_table;
1015 LINK_ELEMENT *list;
1016 VALUE *generated_iseq;
1018 int k, pos, sp, stack_max = 0, line = 0;
1020 /* set label position */
1021 list = FIRST_ELEMENT(anchor);
1022 k = pos = 0;
1023 while (list) {
1024 switch (list->type) {
1025 case ISEQ_ELEMENT_INSN:
1027 iobj = (INSN *)list;
1028 line = iobj->line_no;
1029 pos += insn_data_length(iobj);
1030 k++;
1031 break;
1033 case ISEQ_ELEMENT_LABEL:
1035 lobj = (LABEL *)list;
1036 lobj->position = pos;
1037 lobj->set = Qtrue;
1038 break;
1040 case ISEQ_ELEMENT_NONE:
1042 /* ignore */
1043 break;
1045 case ISEQ_ELEMENT_ADJUST:
1047 ADJUST *adjust = (ADJUST *)list;
1048 if (adjust->line_no != -1) {
1049 pos += 2 /* insn + 1 operand */;
1050 k++;
1052 break;
1054 default:
1055 dump_disasm_list(FIRST_ELEMENT(anchor));
1056 dump_disasm_list(list);
1057 rb_compile_error(RSTRING_PTR(iseq->filename), line,
1058 "error: set_sequence");
1059 break;
1061 list = list->next;
1064 /* make instruction sequence */
1065 generated_iseq = ALLOC_N(VALUE, pos);
1066 insn_info_table = ALLOC_N(struct iseq_insn_info_entry, k);
1068 list = FIRST_ELEMENT(anchor);
1069 k = pos = sp = 0;
1071 while (list) {
1072 switch (list->type) {
1073 case ISEQ_ELEMENT_INSN:
1075 int j, len, insn;
1076 const char *types;
1077 VALUE *operands;
1079 iobj = (INSN *)list;
1081 /* update sp */
1082 sp = calc_sp_depth(sp, iobj);
1083 if (sp > stack_max) {
1084 stack_max = sp;
1087 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
1089 operands = iobj->operands;
1090 insn = iobj->insn_id;
1091 generated_iseq[pos] = insn;
1092 types = insn_op_types(insn);
1093 len = insn_len(insn);
1095 /* operand check */
1096 if (iobj->operand_size != len - 1) {
1097 dump_disasm_list(list);
1098 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1099 "operand size miss! (%d for %d)",
1100 iobj->operand_size, len - 1);
1101 return 0;
1104 for (j = 0; types[j]; j++) {
1105 char type = types[j];
1106 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
1107 switch (type) {
1108 case TS_OFFSET:
1110 /* label(destination position) */
1111 lobj = (LABEL *)operands[j];
1112 if (lobj->set != Qtrue) {
1113 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1114 "unknown label");
1116 if (lobj->sp == -1) {
1117 lobj->sp = sp;
1119 generated_iseq[pos + 1 + j] =
1120 lobj->position - (pos + len);
1121 break;
1123 case TS_CDHASH:
1126 * [obj, label, ...]
1128 int i;
1129 VALUE lits = operands[j];
1130 VALUE map = rb_hash_new();
1132 for (i=0; i < RARRAY_LEN(lits); i+=2) {
1133 VALUE obj = rb_ary_entry(lits, i);
1134 VALUE lv = rb_ary_entry(lits, i+1);
1135 lobj = (LABEL *)(lv & ~1);
1137 if (lobj->set != Qtrue) {
1138 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1139 "unknown label");
1141 rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len)));
1143 generated_iseq[pos + 1 + j] = map;
1144 iseq_add_mark_object(iseq, map);
1145 break;
1147 case TS_LINDEX:
1148 case TS_DINDEX:
1149 case TS_NUM: /* ulong */
1150 generated_iseq[pos + 1 + j] = FIX2INT(operands[j]);
1151 break;
1152 case TS_ISEQ: /* iseq */
1154 VALUE v = operands[j];
1155 rb_iseq_t *block = 0;
1156 if (v) {
1157 GetISeqPtr(v, block);
1159 generated_iseq[pos + 1 + j] = (VALUE)block;
1160 break;
1162 case TS_VALUE: /* VALUE */
1164 VALUE v = operands[j];
1165 generated_iseq[pos + 1 + j] = v;
1166 /* to mark ruby object */
1167 iseq_add_mark_object(iseq, v);
1168 break;
1170 case TS_IC: /* inline cache */
1172 VALUE v = (VALUE)NEW_INLINE_CACHE_ENTRY();
1173 generated_iseq[pos + 1 + j] = v;
1174 iseq_add_mark_object(iseq, v);
1175 break;
1177 case TS_ID: /* ID */
1178 generated_iseq[pos + 1 + j] = SYM2ID(operands[j]);
1179 break;
1180 case TS_GENTRY:
1182 struct global_entry *entry =
1183 (struct global_entry *)(operands[j] & (~1));
1184 generated_iseq[pos + 1 + j] = (VALUE)entry;
1186 break;
1187 default:
1188 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1189 "unknown operand type: %c", type);
1190 return 0;
1193 insn_info_table[k].line_no = iobj->line_no;
1194 insn_info_table[k].position = pos;
1195 insn_info_table[k].sp = sp;
1196 pos += len;
1197 k++;
1198 break;
1200 case ISEQ_ELEMENT_LABEL:
1202 lobj = (LABEL *)list;
1203 if (lobj->sp == -1) {
1204 lobj->sp = sp;
1206 else {
1207 sp = lobj->sp;
1209 break;
1211 case ISEQ_ELEMENT_ADJUST:
1213 ADJUST *adjust = (ADJUST *)list;
1214 int orig_sp = sp;
1216 if (adjust->label) {
1217 sp = adjust->label->sp;
1219 else {
1220 sp = 0;
1223 if (adjust->line_no != -1) {
1224 if (orig_sp - sp > 0) {
1225 insn_info_table[k].line_no = adjust->line_no;
1226 insn_info_table[k].position = pos;
1227 insn_info_table[k].sp = sp;
1228 k++;
1229 generated_iseq[pos++] = BIN(adjuststack);
1230 generated_iseq[pos++] = orig_sp - sp;
1232 else if (orig_sp - sp == 0) {
1233 /* jump to next insn */
1234 insn_info_table[k].line_no = adjust->line_no;
1235 insn_info_table[k].position = pos;
1236 insn_info_table[k].sp = sp;
1237 k++;
1238 generated_iseq[pos++] = BIN(jump);
1239 generated_iseq[pos++] = 0;
1241 else {
1242 rb_bug("iseq_set_sequence: adjust bug");
1245 break;
1247 default:
1248 /* ignore */
1249 break;
1251 list = list->next;
1254 #if 0 /* XXX */
1255 /* this check need dead code elimination */
1256 if (sp != 1) {
1257 rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
1259 #endif
1261 iseq->iseq = (void *)generated_iseq;
1262 iseq->iseq_size = pos;
1263 iseq->insn_info_table = insn_info_table;
1264 iseq->insn_info_size = k;
1265 iseq->stack_max = stack_max;
1267 return COMPILE_OK;
1270 static int
1271 label_get_position(LABEL *lobj)
1273 return lobj->position;
1276 static int
1277 label_get_sp(LABEL *lobj)
1279 return lobj->sp;
1282 static int
1283 iseq_set_exception_table(rb_iseq_t *iseq)
1285 VALUE *tptr, *ptr;
1286 int tlen, i;
1287 struct iseq_catch_table_entry *entry;
1289 tlen = RARRAY_LEN(iseq->compile_data->catch_table_ary);
1290 tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary);
1292 iseq->catch_table = tlen ? ALLOC_N(struct iseq_catch_table_entry, tlen) : 0;
1293 iseq->catch_table_size = tlen;
1295 for (i = 0; i < tlen; i++) {
1296 ptr = RARRAY_PTR(tptr[i]);
1297 entry = &iseq->catch_table[i];
1298 entry->type = ptr[0] & 0xffff;
1299 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
1300 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
1301 entry->iseq = ptr[3];
1303 /* register iseq as mark object */
1304 if (entry->iseq != 0) {
1305 iseq_add_mark_object(iseq, entry->iseq);
1308 /* stack depth */
1309 if (ptr[4]) {
1310 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
1311 entry->cont = label_get_position(lobj);
1312 entry->sp = label_get_sp(lobj);
1314 /* TODO: Dirty Hack! Fix me */
1315 if (entry->type == CATCH_TYPE_RESCUE ||
1316 entry->type == CATCH_TYPE_BREAK ||
1317 (((ptr[0] & 0x10000) == 0)
1318 && entry->type == CATCH_TYPE_NEXT)) {
1319 entry->sp--;
1322 else {
1323 entry->cont = 0;
1327 iseq->compile_data->catch_table_ary = 0; /* free */
1328 return COMPILE_OK;
1332 * set optional argument table
1333 * def foo(a, b=expr1, c=expr2)
1334 * =>
1335 * b:
1336 * expr1
1337 * c:
1338 * expr2
1340 static int
1341 iseq_set_optargs_table(rb_iseq_t *iseq)
1343 int i;
1345 if (iseq->arg_opts != 0) {
1346 for (i = 0; i < iseq->arg_opts; i++) {
1347 iseq->arg_opt_table[i] =
1348 label_get_position((LABEL *)iseq->arg_opt_table[i]);
1351 return COMPILE_OK;
1354 static LINK_ELEMENT *
1355 get_destination_insn(INSN *iobj)
1357 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
1358 LINK_ELEMENT *list;
1360 list = lobj->link.next;
1361 while (list) {
1362 if (list->type == ISEQ_ELEMENT_INSN) {
1363 break;
1365 list = list->next;
1367 return list;
1370 static LINK_ELEMENT *
1371 get_next_insn(INSN *iobj)
1373 LINK_ELEMENT *list = iobj->link.next;
1375 while (list) {
1376 if (list->type == ISEQ_ELEMENT_INSN) {
1377 return list;
1379 list = list->next;
1381 return 0;
1384 static LINK_ELEMENT *
1385 get_prev_insn(INSN *iobj)
1387 LINK_ELEMENT *list = iobj->link.prev;
1389 while (list) {
1390 if (list->type == ISEQ_ELEMENT_INSN) {
1391 return list;
1393 list = list->prev;
1395 return 0;
1398 static int
1399 iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
1401 INSN *iobj = (INSN *)list;
1402 again:
1403 if (iobj->insn_id == BIN(jump)) {
1404 INSN *niobj, *diobj, *piobj;
1406 * useless jump elimination:
1407 * jump LABEL1
1408 * ...
1409 * LABEL1:
1410 * jump LABEL2
1412 * => in this case, first jump instruction should jump tp
1413 * LABEL2 directly
1415 diobj = (INSN *)get_destination_insn(iobj);
1416 niobj = (INSN *)get_next_insn(iobj);
1418 if (diobj == niobj) {
1420 * jump LABEL
1421 * LABEL:
1422 * =>
1423 * LABEL:
1425 REMOVE_ELEM(&iobj->link);
1427 else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
1428 if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
1429 OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0);
1430 goto again;
1433 else if (diobj->insn_id == BIN(leave)) {
1435 * jump LABEL
1436 * ...
1437 * LABEL:
1438 * leave
1439 * =>
1440 * leave
1441 * ...
1442 * LABEL:
1443 * leave
1445 INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave),
1446 diobj->operand_size, diobj->operands);
1447 INSN *popiobj = new_insn_core(iseq, iobj->line_no,
1448 BIN(pop), 0, 0);
1449 /* replace */
1450 REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj);
1451 INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj);
1452 iobj = popiobj;
1455 * useless jump elimination (if/unless destination):
1456 * if L1
1457 * jump L2
1458 * L1:
1459 * ...
1460 * L2:
1462 * ==>
1463 * unless L2
1464 * L1:
1465 * ...
1466 * L2:
1468 else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 &&
1469 (piobj->insn_id == BIN(branchif) ||
1470 piobj->insn_id == BIN(branchunless))) {
1471 if (niobj == (INSN *)get_destination_insn(piobj)) {
1472 piobj->insn_id = (piobj->insn_id == BIN(branchif))
1473 ? BIN(branchunless) : BIN(branchif);
1474 OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0);
1475 REMOVE_ELEM(&iobj->link);
1480 if (iobj->insn_id == BIN(branchif) ||
1481 iobj->insn_id == BIN(branchunless)) {
1483 * if L1
1484 * ...
1485 * L1:
1486 * jump L2
1487 * =>
1488 * if L2
1490 INSN *nobj = (INSN *)get_destination_insn(iobj);
1491 if (nobj->insn_id == BIN(jump)) {
1492 OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
1496 if (do_tailcallopt && iobj->insn_id == BIN(leave)) {
1498 * send ...
1499 * leave
1500 * =>
1501 * send ..., ... | VM_CALL_TAILCALL_BIT, ...
1502 * leave # unreachable
1504 INSN *piobj = (INSN *)get_prev_insn((INSN *)list);
1506 if (piobj->insn_id == BIN(send) &&
1507 piobj->operands[2] == 0 /* block */
1509 piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT);
1512 return COMPILE_OK;
1515 static int
1516 insn_set_specialized_instruction(INSN *iobj, int insn_id)
1518 iobj->insn_id = insn_id;
1519 iobj->operand_size = 0;
1520 return COMPILE_OK;
1523 static int
1524 insn_set_specialized_instruction_with_ic(INSN *iobj, int insn_id, int n)
1526 int i;
1527 iobj->insn_id = insn_id;
1528 iobj->operand_size = n;
1530 /* max of n is 4 */
1531 for (i=0; i<n; i++) {
1532 iobj->operands[i] = Qnil;
1535 return COMPILE_OK;
1539 static int
1540 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
1542 if (iobj->insn_id == BIN(send)) {
1543 ID mid = SYM2ID(OPERAND_AT(iobj, 0));
1544 int argc = FIX2INT(OPERAND_AT(iobj, 1));
1545 VALUE block = OPERAND_AT(iobj, 2);
1546 VALUE flag = OPERAND_AT(iobj, 3);
1548 /* TODO: should be more sophisticated search */
1549 if (block == 0 && flag == INT2FIX(0)) {
1550 if (argc == 0) {
1551 if (mid == idLength) {
1552 insn_set_specialized_instruction(iobj, BIN(opt_length));
1554 else if (mid == idSucc) {
1555 insn_set_specialized_instruction(iobj, BIN(opt_succ));
1557 else if (mid == idNot) {
1558 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_not), 1);
1561 else if (argc == 1) {
1562 if (0) {
1564 else if (mid == idPLUS) {
1565 insn_set_specialized_instruction(iobj, BIN(opt_plus));
1567 else if (mid == idMINUS) {
1568 insn_set_specialized_instruction(iobj, BIN(opt_minus));
1570 else if (mid == idMULT) {
1571 insn_set_specialized_instruction(iobj, BIN(opt_mult));
1573 else if (mid == idDIV) {
1574 insn_set_specialized_instruction(iobj, BIN(opt_div));
1576 else if (mid == idMOD) {
1577 insn_set_specialized_instruction(iobj, BIN(opt_mod));
1579 else if (mid == idEq) {
1580 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_eq), 1);
1582 else if (mid == idNeq) {
1583 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_neq), 2);
1585 else if (mid == idLT) {
1586 insn_set_specialized_instruction(iobj, BIN(opt_lt));
1588 else if (mid == idLE) {
1589 insn_set_specialized_instruction(iobj, BIN(opt_le));
1591 else if (mid == idGT) {
1592 insn_set_specialized_instruction(iobj, BIN(opt_gt));
1594 else if (mid == idGE) {
1595 insn_set_specialized_instruction(iobj, BIN(opt_ge));
1597 else if (mid == idLTLT) {
1598 insn_set_specialized_instruction(iobj, BIN(opt_ltlt));
1600 else if (mid == idAREF) {
1601 insn_set_specialized_instruction(iobj, BIN(opt_aref));
1606 if (argc > 0) {
1607 if (mid == idSend || mid == id__send__ ) {
1608 OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT);
1612 return COMPILE_OK;
1615 static int
1616 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1618 LINK_ELEMENT *list;
1619 const int do_peepholeopt = iseq->compile_data->option->peephole_optimization;
1620 const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization;
1621 const int do_si = iseq->compile_data->option->specialized_instruction;
1622 const int do_ou = iseq->compile_data->option->operands_unification;
1623 list = FIRST_ELEMENT(anchor);
1625 while (list) {
1626 if (list->type == ISEQ_ELEMENT_INSN) {
1627 if (do_peepholeopt) {
1628 iseq_peephole_optimize(iseq, list, do_tailcallopt);
1630 if (do_si) {
1631 iseq_specialized_instruction(iseq, (INSN *)list);
1633 if (do_ou) {
1634 insn_operands_unification((INSN *)list);
1637 list = list->next;
1639 return COMPILE_OK;
1642 #if OPT_INSTRUCTIONS_UNIFICATION
1643 static INSN *
1644 new_unified_insn(rb_iseq_t *iseq,
1645 int insn_id, int size, LINK_ELEMENT *seq_list)
1647 INSN *iobj = 0;
1648 LINK_ELEMENT *list = seq_list;
1649 int i, argc = 0;
1650 VALUE *operands = 0, *ptr = 0;
1653 /* count argc */
1654 for (i = 0; i < size; i++) {
1655 iobj = (INSN *)list;
1656 argc += iobj->operand_size;
1657 list = list->next;
1660 if (argc > 0) {
1661 ptr = operands =
1662 (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
1665 /* copy operands */
1666 list = seq_list;
1667 for (i = 0; i < size; i++) {
1668 iobj = (INSN *)list;
1669 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
1670 ptr += iobj->operand_size;
1671 list = list->next;
1674 return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands);
1676 #endif
1679 * This scheme can get more performance if do this optimize with
1680 * label address resolving.
1681 * It's future work (if compile time was bottle neck).
1683 static int
1684 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1686 #if OPT_INSTRUCTIONS_UNIFICATION
1687 LINK_ELEMENT *list;
1688 INSN *iobj, *niobj;
1689 int id, j, k;
1691 list = FIRST_ELEMENT(anchor);
1692 while (list) {
1693 if (list->type == ISEQ_ELEMENT_INSN) {
1694 iobj = (INSN *)list;
1695 id = iobj->insn_id;
1696 if (unified_insns_data[id] != 0) {
1697 const int *const *entry = unified_insns_data[id];
1698 for (j = 1; j < (int)entry[0]; j++) {
1699 const int *unified = entry[j];
1700 LINK_ELEMENT *li = list->next;
1701 for (k = 2; k < unified[1]; k++) {
1702 if (li->type != ISEQ_ELEMENT_INSN ||
1703 ((INSN *)li)->insn_id != unified[k]) {
1704 goto miss;
1706 li = li->next;
1708 /* matched */
1709 niobj =
1710 new_unified_insn(iseq, unified[0], unified[1] - 1,
1711 list);
1713 /* insert to list */
1714 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
1715 niobj->link.next = li;
1716 if (li) {
1717 li->prev = (LINK_ELEMENT *)niobj;
1720 list->prev->next = (LINK_ELEMENT *)niobj;
1721 list = (LINK_ELEMENT *)niobj;
1722 break;
1723 miss:;
1727 list = list->next;
1729 #endif
1730 return COMPILE_OK;
1733 #if OPT_STACK_CACHING
1735 #define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
1736 #define SC_NEXT(insn) sc_insn_next[insn]
1738 #include "opt_sc.inc"
1740 static int
1741 insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state)
1743 int nstate;
1744 int insn_id;
1746 insn_id = iobj->insn_id;
1747 iobj->insn_id = SC_INSN(insn_id, state);
1748 nstate = SC_NEXT(iobj->insn_id);
1750 if (insn_id == BIN(jump) ||
1751 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
1752 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
1754 if (lobj->sc_state != 0) {
1755 if (lobj->sc_state != nstate) {
1756 dump_disasm_list((LINK_ELEMENT *)iobj);
1757 dump_disasm_list((LINK_ELEMENT *)lobj);
1758 printf("\n-- %d, %d\n", lobj->sc_state, nstate);
1759 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->lineno,
1760 "insn_set_sc_state error\n");
1761 return 0;
1764 else {
1765 lobj->sc_state = nstate;
1767 if (insn_id == BIN(jump)) {
1768 nstate = SCS_XX;
1771 else if (insn_id == BIN(leave)) {
1772 nstate = SCS_XX;
1775 return nstate;
1778 static int
1779 label_set_sc_state(LABEL *lobj, int state)
1781 if (lobj->sc_state != 0) {
1782 if (lobj->sc_state != state) {
1783 state = lobj->sc_state;
1786 else {
1787 lobj->sc_state = state;
1790 return state;
1794 #endif
1796 static int
1797 iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1799 #if OPT_STACK_CACHING
1800 LINK_ELEMENT *list;
1801 int state, insn_id;
1803 /* initialize */
1804 state = SCS_XX;
1805 list = FIRST_ELEMENT(anchor);
1806 /* dump_disasm_list(list); */
1808 /* for each list element */
1809 while (list) {
1810 redo_point:
1811 switch (list->type) {
1812 case ISEQ_ELEMENT_INSN:
1814 INSN *iobj = (INSN *)list;
1815 insn_id = iobj->insn_id;
1817 /* dump_disasm_list(list); */
1819 switch (insn_id) {
1820 case BIN(nop):
1822 /* exception merge point */
1823 if (state != SCS_AX) {
1824 INSN *rpobj =
1825 new_insn_body(iseq, 0, BIN(reput), 0);
1827 /* replace this insn */
1828 REPLACE_ELEM(list, (LINK_ELEMENT *)rpobj);
1829 list = (LINK_ELEMENT *)rpobj;
1830 goto redo_point;
1832 break;
1834 case BIN(swap):
1836 if (state == SCS_AB || state == SCS_BA) {
1837 state = (state == SCS_AB ? SCS_BA : SCS_AB);
1839 REMOVE_ELEM(list);
1840 list = list->next;
1841 goto redo_point;
1843 break;
1845 case BIN(pop):
1847 switch (state) {
1848 case SCS_AX:
1849 case SCS_BX:
1850 state = SCS_XX;
1851 break;
1852 case SCS_AB:
1853 state = SCS_AX;
1854 break;
1855 case SCS_BA:
1856 state = SCS_BX;
1857 break;
1858 case SCS_XX:
1859 goto normal_insn;
1860 default:
1861 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1862 "unreachable");
1864 /* remove useless pop */
1865 REMOVE_ELEM(list);
1866 list = list->next;
1867 goto redo_point;
1869 default:;
1870 /* none */
1871 } /* end of switch */
1872 normal_insn:
1873 state = insn_set_sc_state(iseq, iobj, state);
1874 break;
1876 case ISEQ_ELEMENT_LABEL:
1878 LABEL *lobj;
1879 lobj = (LABEL *)list;
1881 state = label_set_sc_state(lobj, state);
1883 default:
1884 break;
1886 list = list->next;
1888 #endif
1889 return COMPILE_OK;
1894 static int
1895 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int *cntp)
1897 NODE *list = node->nd_next;
1898 VALUE lit = node->nd_lit;
1899 int cnt = 1;
1901 debugp_param("nd_lit", lit);
1902 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
1904 while (list) {
1905 COMPILE(ret, "each string", list->nd_head);
1906 cnt++;
1907 list = list->nd_next;
1909 *cntp = cnt;
1911 return COMPILE_OK;
1914 static int
1915 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
1917 int cnt;
1918 compile_dstr_fragments(iseq, ret, node, &cnt);
1919 ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
1920 return COMPILE_OK;
1923 static int
1924 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
1926 int cnt;
1927 compile_dstr_fragments(iseq, ret, node, &cnt);
1928 ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
1929 return COMPILE_OK;
1932 static int
1933 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
1934 LABEL *then_label, LABEL *else_label)
1936 switch (nd_type(cond)) {
1937 case NODE_AND:
1939 LABEL *label = NEW_LABEL(nd_line(cond));
1940 compile_branch_condition(iseq, ret, cond->nd_1st, label,
1941 else_label);
1942 ADD_LABEL(ret, label);
1943 compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
1944 else_label);
1945 break;
1947 case NODE_OR:
1949 LABEL *label = NEW_LABEL(nd_line(cond));
1950 compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
1951 label);
1952 ADD_LABEL(ret, label);
1953 compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
1954 else_label);
1955 break;
1957 case NODE_LIT: /* NODE_LIT is always not true */
1958 case NODE_TRUE:
1959 case NODE_STR:
1960 /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
1961 ADD_INSNL(ret, nd_line(cond), jump, then_label);
1962 break;
1963 case NODE_FALSE:
1964 case NODE_NIL:
1965 /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
1966 ADD_INSNL(ret, nd_line(cond), jump, else_label);
1967 break;
1968 default:
1969 COMPILE(ret, "branch condition", cond);
1970 ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
1971 ADD_INSNL(ret, nd_line(cond), jump, then_label);
1972 break;
1974 return COMPILE_OK;
1977 static int
1978 compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
1979 VALUE opt_p, int poped)
1981 NODE *node = node_root;
1982 int len = node->nd_alen, line = nd_line(node), i=0;
1983 DECL_ANCHOR(anchor);
1985 INIT_ANCHOR(anchor);
1986 if (nd_type(node) != NODE_ZARRAY) {
1987 while (node) {
1988 if (nd_type(node) != NODE_ARRAY) {
1989 rb_bug("compile_array: This node is not NODE_ARRAY, but %s",
1990 ruby_node_name(nd_type(node)));
1993 i++;
1994 if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
1995 opt_p = Qfalse;
1997 COMPILE_(anchor, "array element", node->nd_head, poped);
1998 node = node->nd_next;
2002 if (len != i) {
2003 if (0) {
2004 rb_bug("node error: compile_array (%d: %d-%d)",
2005 (int)nd_line(node_root), len, i);
2007 len = i;
2010 if (opt_p == Qtrue) {
2011 if (!poped) {
2012 VALUE ary = rb_ary_new();
2013 node = node_root;
2014 while (node) {
2015 rb_ary_push(ary, node->nd_head->nd_lit);
2016 node = node->nd_next;
2019 iseq_add_mark_object_compile_time(iseq, ary);
2020 ADD_INSN1(ret, nd_line(node_root), duparray, ary);
2023 else {
2024 if (!poped) {
2025 ADD_INSN1(anchor, line, newarray, INT2FIX(len));
2027 APPEND_LIST(ret, anchor);
2029 return len;
2032 static VALUE
2033 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, VALUE opt_p)
2035 return compile_array_(iseq, ret, node_root, opt_p, 0);
2038 static VALUE
2039 case_when_optimizable_literal(NODE * node)
2041 switch (nd_type(node)) {
2042 case NODE_LIT: {
2043 VALUE v = node->nd_lit;
2044 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
2045 return v;
2047 break;
2049 case NODE_STR:
2050 return node->nd_lit;
2052 return Qfalse;
2055 static VALUE
2056 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literals)
2058 while (vals) {
2059 VALUE lit;
2060 NODE* val;
2062 val = vals->nd_head;
2064 if (special_literals &&
2065 (lit = case_when_optimizable_literal(val)) != Qfalse) {
2066 rb_ary_push(special_literals, lit);
2067 rb_ary_push(special_literals, (VALUE)(l1) | 1);
2069 else {
2070 special_literals = Qfalse;
2073 COMPILE(cond_seq, "when cond", val);
2074 ADD_INSN1(cond_seq, nd_line(val), topn, INT2FIX(1));
2075 ADD_SEND(cond_seq, nd_line(val), ID2SYM(idEqq), INT2FIX(1));
2076 ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
2077 vals = vals->nd_next;
2079 return special_literals;
2082 static int
2083 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
2085 switch (nd_type(node)) {
2086 case NODE_ATTRASGN: {
2087 INSN *iobj;
2088 VALUE dupidx;
2090 COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node);
2091 POP_ELEMENT(ret); /* pop pop insn */
2092 iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */
2094 dupidx = iobj->operands[1];
2095 dupidx = INT2FIX(FIX2INT(dupidx) + 1);
2096 iobj->operands[1] = dupidx;
2098 ADD_INSN1(ret, nd_line(node), topn, dupidx);
2099 ADD_ELEM(ret, (LINK_ELEMENT *)iobj);
2100 ADD_INSN(ret, nd_line(node), pop); /* result */
2101 ADD_INSN(ret, nd_line(node), pop); /* rhs */
2102 break;
2104 case NODE_MASGN: {
2105 DECL_ANCHOR(anchor);
2106 INIT_ANCHOR(anchor);
2107 COMPILE_POPED(anchor, "nest masgn lhs", node);
2108 REMOVE_ELEM(FIRST_ELEMENT(anchor));
2109 ADD_SEQ(ret, anchor);
2110 break;
2112 default: {
2113 DECL_ANCHOR(anchor);
2114 INIT_ANCHOR(anchor);
2115 COMPILE_POPED(anchor, "masgn lhs", node);
2116 REMOVE_ELEM(FIRST_ELEMENT(anchor));
2117 ADD_SEQ(ret, anchor);
2121 return COMPILE_OK;
2124 static void
2125 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn)
2127 if (lhsn) {
2128 compile_massign_opt_lhs(iseq, ret, lhsn->nd_next);
2129 compile_massign_lhs(iseq, ret, lhsn->nd_head);
2133 static int
2134 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2135 NODE *rhsn, NODE *orig_lhsn)
2137 VALUE mem[64];
2138 const int memsize = sizeof(mem) / sizeof(mem[0]);
2139 int memindex = 0;
2140 int llen = 0, rlen = 0;
2141 int i;
2142 NODE *lhsn = orig_lhsn;
2144 #define MEMORY(v) { \
2145 int i; \
2146 if (memindex == memsize) return 0; \
2147 for (i=0; i<memindex; i++) { \
2148 if (mem[i] == (v)) return 0; \
2150 mem[memindex++] = (v); \
2153 if (rhsn == 0 || nd_type(rhsn) != NODE_ARRAY) {
2154 return 0;
2157 while (lhsn) {
2158 NODE *ln = lhsn->nd_head;
2159 switch (nd_type(ln)) {
2160 case NODE_LASGN:
2161 MEMORY(ln->nd_vid);
2162 break;
2163 case NODE_DASGN:
2164 case NODE_DASGN_CURR:
2165 case NODE_IASGN:
2166 case NODE_IASGN2:
2167 case NODE_CVASGN:
2168 MEMORY(ln->nd_vid);
2169 break;
2170 default:
2171 return 0;
2173 lhsn = lhsn->nd_next;
2174 llen++;
2177 while (rhsn) {
2178 if (llen <= rlen) {
2179 COMPILE_POPED(ret, "masgn val (poped)", rhsn->nd_head);
2181 else {
2182 COMPILE(ret, "masgn val", rhsn->nd_head);
2184 rhsn = rhsn->nd_next;
2185 rlen++;
2188 if (llen > rlen) {
2189 for (i=0; i<llen-rlen; i++) {
2190 ADD_INSN(ret, nd_line(orig_lhsn), putnil);
2194 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
2195 return 1;
2198 static int
2199 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped)
2201 NODE *rhsn = node->nd_value;
2202 NODE *splatn = node->nd_args;
2203 NODE *lhsn = node->nd_head;
2204 int lhs_splat = (splatn && (VALUE)splatn != (VALUE)-1) ? 1 : 0;
2206 if (!poped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
2207 int llen = 0;
2208 DECL_ANCHOR(lhsseq);
2210 INIT_ANCHOR(lhsseq);
2212 while (lhsn) {
2213 compile_massign_lhs(iseq, lhsseq, lhsn->nd_head);
2214 llen += 1;
2215 lhsn = lhsn->nd_next;
2218 COMPILE(ret, "normal masgn rhs", rhsn);
2220 if (!poped) {
2221 ADD_INSN(ret, nd_line(node), dup);
2224 ADD_INSN2(ret, nd_line(node), expandarray,
2225 INT2FIX(llen), INT2FIX(lhs_splat));
2226 ADD_SEQ(ret, lhsseq);
2228 if (lhs_splat) {
2229 if (nd_type(splatn) == NODE_POSTARG) {
2230 /*a, b, *r, p1, p2 */
2231 NODE *postn = splatn->nd_2nd;
2232 NODE *restn = splatn->nd_1st;
2233 int num = postn->nd_alen;
2234 int flag = 0x02 | (((VALUE)restn == (VALUE)-1) ? 0x00 : 0x01);
2236 ADD_INSN2(ret, nd_line(splatn), expandarray,
2237 INT2FIX(num), INT2FIX(flag));
2239 if ((VALUE)restn != (VALUE)-1) {
2240 compile_massign_lhs(iseq, ret, restn);
2242 while (postn) {
2243 compile_massign_lhs(iseq, ret, postn->nd_head);
2244 postn = postn->nd_next;
2247 else {
2248 /* a, b, *r */
2249 compile_massign_lhs(iseq, ret, splatn);
2253 return COMPILE_OK;
2256 static int
2257 compile_colon2(rb_iseq_t *iseq, NODE * node,
2258 LINK_ANCHOR *pref, LINK_ANCHOR *body)
2260 switch (nd_type(node)) {
2261 case NODE_CONST:
2262 debugi("compile_colon2 - colon", node->nd_vid);
2263 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
2264 break;
2265 case NODE_COLON3:
2266 debugi("compile_colon2 - colon3", node->nd_mid);
2267 ADD_INSN(body, nd_line(node), pop);
2268 ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
2269 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2270 break;
2271 case NODE_COLON2:
2272 compile_colon2(iseq, node->nd_head, pref, body);
2273 debugi("compile_colon2 - colon2", node->nd_mid);
2274 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2275 break;
2276 default:
2277 COMPILE(pref, "const colon2 prefix", node);
2278 break;
2280 return COMPILE_OK;
2283 static int
2284 compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
2286 if (cpath->nd_head) {
2287 COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
2289 else if (nd_type(cpath) == NODE_COLON2) {
2290 COMPILE(ret, "cpath (NODE_COLON2)", cpath->nd_head);
2292 else {
2293 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
2295 return COMPILE_OK;
2298 static int
2299 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2300 NODE *node, LABEL **lfinish, VALUE needstr)
2302 char *estr = 0;
2303 enum node_type type;
2305 switch (type = nd_type(node)) {
2307 /* easy literals */
2308 case NODE_NIL:
2309 estr = "nil";
2310 break;
2311 case NODE_SELF:
2312 estr = "self";
2313 break;
2314 case NODE_TRUE:
2315 estr = "true";
2316 break;
2317 case NODE_FALSE:
2318 estr = "false";
2319 break;
2321 case NODE_ARRAY:{
2322 NODE *vals = node;
2324 do {
2325 defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
2327 if (lfinish[1]) {
2328 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2330 else {
2331 LABEL *lcont = NEW_LABEL(nd_line(node));
2332 lfinish[1] = NEW_LABEL(nd_line(node));
2333 ADD_INSNL(ret, nd_line(node), branchif, lcont);
2334 ADD_LABEL(ret, lfinish[1]);
2335 ADD_INSN(ret, nd_line(node), putnil);
2336 ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
2337 ADD_LABEL(ret, lcont);
2339 } while ((vals = vals->nd_next) != NULL);
2341 case NODE_STR:
2342 case NODE_LIT:
2343 case NODE_ZARRAY:
2344 estr = "expression";
2345 break;
2347 /* variables */
2348 case NODE_LVAR:
2349 case NODE_DVAR:
2350 estr = "local-variable";
2351 break;
2353 case NODE_IVAR:
2354 ADD_INSN(ret, nd_line(node), putnil);
2355 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR),
2356 ID2SYM(node->nd_vid), needstr);
2357 return 1;
2359 case NODE_GVAR:
2360 ADD_INSN(ret, nd_line(node), putnil);
2361 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR),
2362 ((VALUE)node->nd_entry) | 1, needstr);
2363 return 1;
2365 case NODE_CVAR:
2366 ADD_INSN(ret, nd_line(node), putnil);
2367 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR),
2368 ID2SYM(node->nd_vid), needstr);
2369 return 1;
2371 case NODE_CONST:
2372 ADD_INSN(ret, nd_line(node), putnil);
2373 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2374 ID2SYM(node->nd_vid), needstr);
2375 return 1;
2376 case NODE_COLON2:
2377 if (!lfinish[1]) {
2378 lfinish[1] = NEW_LABEL(nd_line(node));
2380 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
2381 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2383 if (rb_is_const_id(node->nd_mid)) {
2384 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2385 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2386 ID2SYM(node->nd_mid), needstr);
2388 else {
2389 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2390 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2391 ID2SYM(node->nd_mid), needstr);
2393 return 1;
2394 case NODE_COLON3:
2395 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
2396 ADD_INSN3(ret, nd_line(node), defined,
2397 INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
2398 return 1;
2400 /* method dispatch */
2401 case NODE_CALL:
2402 case NODE_VCALL:
2403 case NODE_FCALL:
2404 case NODE_ATTRASGN:{
2405 int self = Qtrue;
2407 switch (type) {
2408 case NODE_ATTRASGN:
2409 if (node->nd_recv == (NODE *)1) break;
2410 case NODE_CALL:
2411 self = Qfalse;
2412 break;
2413 default:
2414 /* through */;
2416 if (!lfinish[1]) {
2417 lfinish[1] = NEW_LABEL(nd_line(node));
2419 if (node->nd_args) {
2420 defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
2421 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2423 if (!self) {
2424 LABEL *lstart = NEW_LABEL(nd_line(node));
2425 LABEL *lend = NEW_LABEL(nd_line(node));
2426 VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
2427 rb_str_concat(rb_str_new2
2428 ("defined guard in "),
2429 iseq->name),
2430 ISEQ_TYPE_DEFINED_GUARD);
2432 defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
2433 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2435 ADD_LABEL(ret, lstart);
2436 COMPILE(ret, "defined/recv", node->nd_recv);
2437 ADD_LABEL(ret, lend);
2438 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
2439 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2440 ID2SYM(node->nd_mid), needstr);
2442 else {
2443 ADD_INSN(ret, nd_line(node), putself);
2444 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
2445 ID2SYM(node->nd_mid), needstr);
2447 return 1;
2450 case NODE_YIELD:
2451 ADD_INSN(ret, nd_line(node), putnil);
2452 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0,
2453 needstr);
2454 return 1;
2456 case NODE_BACK_REF:
2457 case NODE_NTH_REF:
2458 ADD_INSN(ret, nd_line(node), putnil);
2459 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
2460 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
2461 needstr);
2462 return 1;
2464 case NODE_ZSUPER:
2465 ADD_INSN(ret, nd_line(node), putnil);
2466 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
2467 needstr);
2468 return 1;
2470 case NODE_OP_ASGN1:
2471 case NODE_OP_ASGN2:
2472 case NODE_MASGN:
2473 case NODE_LASGN:
2474 case NODE_DASGN:
2475 case NODE_DASGN_CURR:
2476 case NODE_GASGN:
2477 case NODE_IASGN:
2478 case NODE_CDECL:
2479 case NODE_CVDECL:
2480 case NODE_CVASGN:
2481 estr = "assignment";
2482 break;
2484 default:{
2485 LABEL *lstart = NEW_LABEL(nd_line(node));
2486 LABEL *lend = NEW_LABEL(nd_line(node));
2487 VALUE ensure = NEW_CHILD_ISEQVAL(NEW_NIL(),
2488 rb_str_concat(rb_str_new2
2489 ("defined guard in "),
2490 iseq->name),
2491 ISEQ_TYPE_DEFINED_GUARD);
2493 ADD_LABEL(ret, lstart);
2494 COMPILE(ret, "defined expr (others)", node);
2495 if (!lfinish[1]) {
2496 lfinish[1] = NEW_LABEL(nd_line(node));
2498 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2499 if (needstr) {
2500 ADD_INSN1(ret, nd_line(node), putstring, rb_str_new2("expression"));
2502 else {
2503 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2505 ADD_LABEL(ret, lend);
2507 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, lstart, lend, ensure, lfinish[1]);
2508 return 1;
2509 } /* end of default */
2512 if (estr != 0) {
2513 if (needstr != Qfalse) {
2514 VALUE str = rb_str_new2(estr);
2515 ADD_INSN1(ret, nd_line(node), putstring, str);
2516 iseq_add_mark_object_compile_time(iseq, str);
2518 else {
2519 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2521 return 1;
2523 return 0;
2526 #define BUFSIZE 0x100
2528 static VALUE
2529 make_name_for_block(rb_iseq_t *iseq)
2531 if (iseq->parent_iseq == 0) {
2532 return rb_sprintf("block in %s", RSTRING_PTR(iseq->name));
2534 else {
2535 int level = 1;
2536 rb_iseq_t *ip = iseq;
2537 while (ip->local_iseq != ip) {
2538 ip = ip->parent_iseq;
2539 level++;
2541 return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->name));
2545 static void
2546 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
2547 LABEL *lstart, LABEL *lend)
2549 struct ensure_range *ne =
2550 compile_data_alloc(iseq, sizeof(struct ensure_range));
2552 while (erange->next != 0) {
2553 erange = erange->next;
2555 ne->next = 0;
2556 ne->begin = lend;
2557 ne->end = erange->end;
2558 erange->end = lstart;
2560 erange->next = ne;
2563 static void
2564 add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq)
2566 struct iseq_compile_data_ensure_node_stack *enlp =
2567 iseq->compile_data->ensure_node_stack;
2568 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
2569 DECL_ANCHOR(ensure);
2571 INIT_ANCHOR(ensure);
2572 while (enlp) {
2573 DECL_ANCHOR(ensure_part);
2574 LABEL *lstart = NEW_LABEL(0);
2575 LABEL *lend = NEW_LABEL(0);
2577 INIT_ANCHOR(ensure_part);
2578 add_ensure_range(iseq, enlp->erange, lstart, lend);
2580 iseq->compile_data->ensure_node_stack = enlp->prev;
2581 ADD_LABEL(ensure_part, lstart);
2582 COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
2583 ADD_LABEL(ensure_part, lend);
2585 ADD_SEQ(ensure, ensure_part);
2586 enlp = enlp->prev;
2588 iseq->compile_data->ensure_node_stack = prev_enlp;
2589 ADD_SEQ(ret, ensure);
2592 static VALUE
2593 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned long *flag)
2595 VALUE argc = INT2FIX(0);
2596 int nsplat = 0;
2597 DECL_ANCHOR(arg_block);
2598 DECL_ANCHOR(args_splat);
2600 INIT_ANCHOR(arg_block);
2601 INIT_ANCHOR(args_splat);
2602 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
2603 COMPILE(arg_block, "block", argn->nd_body);
2604 *flag |= VM_CALL_ARGS_BLOCKARG_BIT;
2605 argn = argn->nd_head;
2608 setup_argn:
2609 if (argn) {
2610 switch (nd_type(argn)) {
2611 case NODE_SPLAT: {
2612 COMPILE(args, "args (splat)", argn->nd_head);
2613 argc = INT2FIX(1);
2614 nsplat++;
2615 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2616 break;
2618 case NODE_ARGSCAT:
2619 case NODE_ARGSPUSH: {
2620 int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
2621 DECL_ANCHOR(tmp);
2623 INIT_ANCHOR(tmp);
2624 COMPILE(tmp, "args (cat: splat)", argn->nd_body);
2625 if (next_is_array && nsplat == 0) {
2626 /* none */
2628 else {
2629 if (nd_type(argn) == NODE_ARGSCAT) {
2630 ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
2632 else {
2633 ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1));
2636 INSERT_LIST(args_splat, tmp);
2637 nsplat++;
2638 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2640 if (next_is_array) {
2641 argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) + 1);
2642 POP_ELEMENT(args);
2644 else {
2645 argn = argn->nd_head;
2646 goto setup_argn;
2648 break;
2650 case NODE_ARRAY: {
2651 argc = INT2FIX(compile_array(iseq, args, argn, Qfalse));
2652 POP_ELEMENT(args);
2653 break;
2655 default: {
2656 rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn)));
2661 if (nsplat > 1) {
2662 int i;
2663 for (i=1; i<nsplat; i++) {
2664 ADD_INSN(args_splat, nd_line(args), concatarray);
2668 if (!LIST_SIZE_ZERO(args_splat)) {
2669 ADD_SEQ(args, args_splat);
2672 if (*flag & VM_CALL_ARGS_BLOCKARG_BIT) {
2673 ADD_SEQ(args, arg_block);
2675 return argc;
2680 compile each node
2682 self: InstructionSequence
2683 node: Ruby compiled node
2684 poped: This node will be poped
2686 static int
2687 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
2689 enum node_type type;
2691 if (node == 0) {
2692 if (!poped) {
2693 debugs("node: NODE_NIL(implicit)\n");
2694 ADD_INSN(ret, iseq->compile_data->last_line, putnil);
2696 return COMPILE_OK;
2699 iseq->compile_data->last_line = nd_line(node);
2700 debug_node_start(node);
2702 type = nd_type(node);
2704 if (node->flags & NODE_FL_NEWLINE) {
2705 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_LINE);
2708 switch (type) {
2709 case NODE_BLOCK:{
2710 while (node && nd_type(node) == NODE_BLOCK) {
2711 COMPILE_(ret, "BLOCK body", node->nd_head,
2712 (node->nd_next == 0 && poped == 0) ? 0 : 1);
2713 node = node->nd_next;
2715 if (node) {
2716 COMPILE_(ret, "BLOCK next", node->nd_next, poped);
2718 break;
2720 case NODE_IF:{
2721 DECL_ANCHOR(cond_seq);
2722 DECL_ANCHOR(then_seq);
2723 DECL_ANCHOR(else_seq);
2724 LABEL *then_label, *else_label, *end_label;
2726 INIT_ANCHOR(cond_seq);
2727 INIT_ANCHOR(then_seq);
2728 INIT_ANCHOR(else_seq);
2729 then_label = NEW_LABEL(nd_line(node));
2730 else_label = NEW_LABEL(nd_line(node));
2731 end_label = NEW_LABEL(nd_line(node));
2733 compile_branch_condition(iseq, cond_seq, node->nd_cond,
2734 then_label, else_label);
2735 COMPILE_(then_seq, "then", node->nd_body, poped);
2736 COMPILE_(else_seq, "else", node->nd_else, poped);
2738 ADD_SEQ(ret, cond_seq);
2740 ADD_LABEL(ret, then_label);
2741 ADD_SEQ(ret, then_seq);
2742 ADD_INSNL(ret, nd_line(node), jump, end_label);
2744 ADD_LABEL(ret, else_label);
2745 ADD_SEQ(ret, else_seq);
2747 ADD_LABEL(ret, end_label);
2749 break;
2751 case NODE_CASE:{
2752 NODE *vals;
2753 NODE *tempnode = node;
2754 LABEL *endlabel, *elselabel;
2755 DECL_ANCHOR(head);
2756 DECL_ANCHOR(body_seq);
2757 DECL_ANCHOR(cond_seq);
2758 VALUE special_literals = rb_ary_new();
2760 INIT_ANCHOR(head);
2761 INIT_ANCHOR(body_seq);
2762 INIT_ANCHOR(cond_seq);
2763 if (node->nd_head == 0) {
2764 COMPILE_(ret, "when", node->nd_body, poped);
2765 break;
2767 COMPILE(head, "case base", node->nd_head);
2769 node = node->nd_body;
2770 type = nd_type(node);
2772 if (type != NODE_WHEN) {
2773 COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
2776 endlabel = NEW_LABEL(nd_line(node));
2777 elselabel = NEW_LABEL(nd_line(node));
2779 ADD_SEQ(ret, head); /* case VAL */
2781 while (type == NODE_WHEN) {
2782 LABEL *l1;
2784 l1 = NEW_LABEL(nd_line(node));
2785 ADD_LABEL(body_seq, l1);
2786 ADD_INSN(body_seq, nd_line(node), pop);
2787 COMPILE_(body_seq, "when body", node->nd_body, poped);
2788 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2790 vals = node->nd_head;
2791 if (vals) {
2792 switch (nd_type(vals)) {
2793 case NODE_ARRAY:
2794 special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals);
2795 break;
2796 case NODE_SPLAT:
2797 case NODE_ARGSCAT:
2798 case NODE_ARGSPUSH:
2799 special_literals = 0;
2800 COMPILE(cond_seq, "when/cond splat", vals);
2801 ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
2802 ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
2803 break;
2804 default:
2805 rb_bug("NODE_CASE: unknown node (%s)",
2806 ruby_node_name(nd_type(vals)));
2809 else {
2810 rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
2813 node = node->nd_next;
2814 if (!node) {
2815 break;
2817 type = nd_type(node);
2819 /* else */
2820 if (node) {
2821 ADD_LABEL(cond_seq, elselabel);
2822 ADD_INSN(cond_seq, nd_line(node), pop);
2823 COMPILE_(cond_seq, "else", node, poped);
2824 ADD_INSNL(cond_seq, nd_line(node), jump, endlabel);
2826 else {
2827 debugs("== else (implicit)\n");
2828 ADD_LABEL(cond_seq, elselabel);
2829 ADD_INSN(cond_seq, nd_line(tempnode), pop);
2830 if (!poped) {
2831 ADD_INSN(cond_seq, nd_line(tempnode), putnil);
2833 ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
2836 if (special_literals) {
2837 ADD_INSN(ret, nd_line(tempnode), dup);
2838 ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch,
2839 special_literals, elselabel);
2840 iseq_add_mark_object_compile_time(iseq, special_literals);
2843 ADD_SEQ(ret, cond_seq);
2844 ADD_SEQ(ret, body_seq);
2845 ADD_LABEL(ret, endlabel);
2846 break;
2848 case NODE_WHEN:{
2849 NODE *vals;
2850 NODE *val;
2851 NODE *orig_node = node;
2852 LABEL *endlabel;
2853 DECL_ANCHOR(body_seq);
2855 INIT_ANCHOR(body_seq);
2856 endlabel = NEW_LABEL(nd_line(node));
2858 while (node && nd_type(node) == NODE_WHEN) {
2859 LABEL *l1 = NEW_LABEL(nd_line(node));
2860 ADD_LABEL(body_seq, l1);
2861 COMPILE_(body_seq, "when", node->nd_body, poped);
2862 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2864 vals = node->nd_head;
2865 if (vals && nd_type(vals) == NODE_ARRAY) {
2866 while (vals) {
2867 val = vals->nd_head;
2868 COMPILE(ret, "when2", val);
2869 ADD_INSNL(ret, nd_line(val), branchif, l1);
2870 vals = vals->nd_next;
2873 else if (nd_type(vals) == NODE_SPLAT ||
2874 nd_type(vals) == NODE_ARGSCAT ||
2875 nd_type(vals) == NODE_ARGSPUSH) {
2877 NODE *val = vals->nd_head;
2879 if (nd_type(vals) == NODE_ARGSCAT || nd_type(vals) == NODE_ARGSPUSH) {
2880 NODE *vs = vals->nd_head;
2881 val = vals->nd_body;
2883 while (vs) {
2884 NODE* val = vs->nd_head;
2885 COMPILE(ret, "when/argscat", val);
2886 ADD_INSNL(ret, nd_line(val), branchif, l1);
2887 vs = vs->nd_next;
2891 ADD_INSN(ret, nd_line(val), putnil);
2892 COMPILE(ret, "when2/splat", val);
2893 ADD_INSN1(ret, nd_line(val), checkincludearray, Qfalse);
2894 ADD_INSN(ret, nd_line(val), pop);
2895 ADD_INSNL(ret, nd_line(val), branchif, l1);
2897 else {
2898 rb_bug("err");
2900 node = node->nd_next;
2902 /* else */
2903 COMPILE_(ret, "else", node, poped);
2904 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
2906 ADD_SEQ(ret, body_seq);
2907 ADD_LABEL(ret, endlabel);
2909 break;
2911 case NODE_OPT_N:
2912 case NODE_WHILE:
2913 case NODE_UNTIL:{
2914 LABEL *prev_start_label = iseq->compile_data->start_label;
2915 LABEL *prev_end_label = iseq->compile_data->end_label;
2916 LABEL *prev_redo_label = iseq->compile_data->redo_label;
2917 VALUE prev_loopval_popped = iseq->compile_data->loopval_popped;
2919 struct iseq_compile_data_ensure_node_stack *enlp =
2920 iseq->compile_data->ensure_node_stack;
2922 LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(nd_line(node)); /* next */
2923 LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(nd_line(node)); /* redo */
2924 LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(nd_line(node)); /* break */
2925 LABEL *end_label = NEW_LABEL(nd_line(node));
2927 iseq->compile_data->loopval_popped = 0;
2928 iseq->compile_data->ensure_node_stack = 0;
2930 if (type == NODE_OPT_N || node->nd_state == 1) {
2931 ADD_INSNL(ret, nd_line(node), jump, next_label);
2934 ADD_LABEL(ret, redo_label);
2935 COMPILE_POPED(ret, "while body", node->nd_body);
2936 ADD_LABEL(ret, next_label); /* next */
2938 if (type == NODE_WHILE) {
2939 compile_branch_condition(iseq, ret, node->nd_cond,
2940 redo_label, end_label);
2942 else if (type == NODE_UNTIL) {
2943 /* untile */
2944 compile_branch_condition(iseq, ret, node->nd_cond,
2945 end_label, redo_label);
2947 else {
2948 ADD_CALL_RECEIVER(ret, nd_line(node));
2949 ADD_CALL(ret, nd_line(node), ID2SYM(idGets), INT2FIX(0));
2950 ADD_INSNL(ret, nd_line(node), branchif, redo_label);
2951 /* opt_n */
2954 ADD_LABEL(ret, end_label);
2956 if (node->nd_state == Qundef) {
2957 /* ADD_INSN(ret, nd_line(node), putundef); */
2958 rb_bug("unsupported: putundef");
2960 else {
2961 ADD_INSN(ret, nd_line(node), putnil);
2964 ADD_LABEL(ret, break_label); /* braek */
2966 if (poped) {
2967 ADD_INSN(ret, nd_line(node), pop);
2970 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
2971 0, break_label);
2972 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT | 0x10000, redo_label,
2973 break_label, 0, iseq->compile_data->start_label);
2974 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
2975 iseq->compile_data->redo_label);
2977 iseq->compile_data->start_label = prev_start_label;
2978 iseq->compile_data->end_label = prev_end_label;
2979 iseq->compile_data->redo_label = prev_redo_label;
2980 iseq->compile_data->loopval_popped = prev_loopval_popped;
2981 iseq->compile_data->ensure_node_stack = enlp;
2982 break;
2984 case NODE_ITER:
2985 case NODE_FOR:{
2986 VALUE prevblock = iseq->compile_data->current_block;
2987 LABEL *retry_label = NEW_LABEL(nd_line(node));
2988 LABEL *retry_end_l = NEW_LABEL(nd_line(node));
2989 ID mid = 0;
2991 ADD_LABEL(ret, retry_label);
2992 if (nd_type(node) == NODE_FOR) {
2993 COMPILE(ret, "iter caller (for)", node->nd_iter);
2995 iseq->compile_data->current_block =
2996 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
2997 ISEQ_TYPE_BLOCK);
2999 mid = idEach;
3000 ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
3001 iseq->compile_data->current_block, INT2FIX(0));
3003 else {
3004 iseq->compile_data->current_block =
3005 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3006 ISEQ_TYPE_BLOCK);
3007 COMPILE(ret, "iter caller", node->nd_iter);
3009 ADD_LABEL(ret, retry_end_l);
3011 if (poped) {
3012 ADD_INSN(ret, nd_line(node), pop);
3015 iseq->compile_data->current_block = prevblock;
3017 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
3019 break;
3021 case NODE_BREAK:{
3022 unsigned long level = 0;
3024 if (iseq->compile_data->redo_label != 0) {
3025 /* while/until */
3026 LABEL *splabel = NEW_LABEL(0);
3027 ADD_LABEL(ret, splabel);
3028 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3029 COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
3030 add_ensure_iseq(ret, iseq);
3031 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3032 ADD_ADJUST_RESTORE(ret, splabel);
3034 if (!poped) {
3035 ADD_INSN(ret, nd_line(node), putnil);
3038 else if (iseq->type == ISEQ_TYPE_BLOCK) {
3039 break_by_insn:
3040 /* escape from block */
3041 COMPILE(ret, "break val (block)", node->nd_stts);
3042 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x02) /* TAG_BREAK */ );
3043 if (poped) {
3044 ADD_INSN(ret, nd_line(node), pop);
3047 else if (iseq->type == ISEQ_TYPE_EVAL) {
3048 break_in_eval:
3049 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
3051 else {
3052 rb_iseq_t *ip = iseq->parent_iseq;
3053 while (ip) {
3054 level++;
3055 if (ip->compile_data->redo_label != 0) {
3056 level = 0x8000;
3057 if (ip->compile_data->loopval_popped == 0) {
3058 /* need value */
3059 level |= 0x4000;
3061 goto break_by_insn;
3063 else if (ip->type == ISEQ_TYPE_BLOCK) {
3064 level <<= 16;
3065 goto break_by_insn;
3067 else if (ip->type == ISEQ_TYPE_EVAL) {
3068 goto break_in_eval;
3070 ip = ip->parent_iseq;
3072 COMPILE_ERROR((ERROR_ARGS "Invalid break"));
3074 break;
3076 case NODE_NEXT:{
3077 unsigned long level = 0;
3079 if (iseq->compile_data->redo_label != 0) {
3080 LABEL *splabel = NEW_LABEL(0);
3081 debugs("next in while loop\n");
3082 ADD_LABEL(ret, splabel);
3083 COMPILE(ret, "next val/valid syntax?", node->nd_stts);
3084 add_ensure_iseq(ret, iseq);
3085 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3086 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3087 ADD_ADJUST_RESTORE(ret, splabel);
3089 else if (iseq->compile_data->end_label) {
3090 LABEL *splabel = NEW_LABEL(0);
3091 debugs("next in block\n");
3092 ADD_LABEL(ret, splabel);
3093 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3094 COMPILE(ret, "next val", node->nd_stts);
3095 add_ensure_iseq(ret, iseq);
3096 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3097 ADD_ADJUST_RESTORE(ret, splabel);
3099 if (!poped) {
3100 ADD_INSN(ret, nd_line(node), putnil);
3103 else if (iseq->type == ISEQ_TYPE_EVAL) {
3104 next_in_eval:
3105 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
3107 else {
3108 rb_iseq_t *ip;
3109 ip = iseq;
3110 while (ip) {
3111 level = 0x8000;
3112 if (ip->compile_data->redo_label != 0) {
3113 /* while loop */
3114 break;
3116 else if (ip->type == ISEQ_TYPE_BLOCK) {
3117 level |= 0x4000;
3118 break;
3120 else if (ip->type == ISEQ_TYPE_EVAL) {
3121 goto next_in_eval;
3123 ip = ip->parent_iseq;
3125 if (ip != 0) {
3126 COMPILE(ret, "next val", node->nd_stts);
3127 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x03) /* TAG_NEXT */ );
3129 if (poped) {
3130 ADD_INSN(ret, nd_line(node), pop);
3133 else {
3134 COMPILE_ERROR((ERROR_ARGS "Invalid next"));
3137 break;
3139 case NODE_REDO:{
3140 if (iseq->compile_data->redo_label) {
3141 LABEL *splabel = NEW_LABEL(0);
3142 debugs("redo in while");
3143 ADD_LABEL(ret, splabel);
3144 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3145 add_ensure_iseq(ret, iseq);
3146 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->redo_label);
3147 ADD_ADJUST_RESTORE(ret, splabel);
3149 else if (iseq->type == ISEQ_TYPE_EVAL) {
3150 redo_in_eval:
3151 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
3153 else if (iseq->compile_data->start_label) {
3154 LABEL *splabel = NEW_LABEL(0);
3156 debugs("redo in block");
3157 ADD_LABEL(ret, splabel);
3158 add_ensure_iseq(ret, iseq);
3159 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3160 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3161 ADD_ADJUST_RESTORE(ret, splabel);
3163 if (!poped) {
3164 ADD_INSN(ret, nd_line(node), putnil);
3167 else {
3168 rb_iseq_t *ip;
3169 unsigned long level;
3170 level = 0x8000 | 0x4000;
3171 ip = iseq;
3172 while (ip) {
3173 if (ip->compile_data->redo_label != 0) {
3174 break;
3176 else if (ip->type == ISEQ_TYPE_BLOCK) {
3177 break;
3179 else if (ip->type == ISEQ_TYPE_EVAL) {
3180 goto redo_in_eval;
3182 ip = ip->parent_iseq;
3184 if (ip != 0) {
3185 ADD_INSN(ret, nd_line(node), putnil);
3186 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x05) /* TAG_REDO */ );
3188 if (poped) {
3189 ADD_INSN(ret, nd_line(node), pop);
3192 else {
3193 COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
3196 break;
3198 case NODE_RETRY:{
3199 if (iseq->type == ISEQ_TYPE_RESCUE) {
3200 ADD_INSN(ret, nd_line(node), putnil);
3201 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x04) /* TAG_RETRY */ );
3203 if (poped) {
3204 ADD_INSN(ret, nd_line(node), pop);
3207 else {
3208 COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
3210 break;
3212 case NODE_BEGIN:{
3213 COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
3214 break;
3216 case NODE_RESCUE:{
3217 LABEL *lstart = NEW_LABEL(nd_line(node));
3218 LABEL *lend = NEW_LABEL(nd_line(node));
3219 LABEL *lcont = NEW_LABEL(nd_line(node));
3220 VALUE rescue = NEW_CHILD_ISEQVAL(
3221 node->nd_resq,
3222 rb_str_concat(rb_str_new2("rescue in "), iseq->name),
3223 ISEQ_TYPE_RESCUE);
3225 ADD_LABEL(ret, lstart);
3226 COMPILE(ret, "rescue head", node->nd_head);
3227 ADD_LABEL(ret, lend);
3228 if (node->nd_else) {
3229 ADD_INSN(ret, nd_line(node), pop);
3230 COMPILE(ret, "rescue else", node->nd_else);
3232 ADD_INSN(ret, nd_line(node), nop);
3233 ADD_LABEL(ret, lcont);
3235 if (poped) {
3236 ADD_INSN(ret, nd_line(node), pop);
3239 /* resgister catch entry */
3240 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
3241 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
3242 break;
3244 case NODE_RESBODY:{
3245 NODE *resq = node;
3246 NODE *narg;
3247 LABEL *label_miss, *label_hit;
3249 while (resq) {
3250 label_miss = NEW_LABEL(nd_line(node));
3251 label_hit = NEW_LABEL(nd_line(node));
3253 narg = resq->nd_args;
3254 if (narg) {
3255 switch (nd_type(narg)) {
3256 case NODE_ARRAY:
3257 while (narg) {
3258 COMPILE(ret, "rescue arg", narg->nd_head);
3259 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3260 INT2FIX(0));
3261 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3262 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3263 narg = narg->nd_next;
3265 break;
3266 case NODE_SPLAT:
3267 case NODE_ARGSCAT:
3268 case NODE_ARGSPUSH:
3269 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3270 INT2FIX(0));
3271 COMPILE(ret, "rescue/cond splat", narg);
3272 ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
3273 ADD_INSN(ret, nd_line(node), swap);
3274 ADD_INSN(ret, nd_line(node), pop);
3275 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3276 break;
3277 default:
3278 rb_bug("NODE_RESBODY: unknown node (%s)",
3279 ruby_node_name(nd_type(narg)));
3282 else {
3283 ADD_INSN1(ret, nd_line(node), putobject,
3284 rb_eStandardError);
3285 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3286 INT2FIX(0));
3287 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3288 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3290 ADD_INSNL(ret, nd_line(node), jump, label_miss);
3291 ADD_LABEL(ret, label_hit);
3292 COMPILE(ret, "resbody body", resq->nd_body);
3293 if (iseq->compile_data->option->tailcall_optimization) {
3294 ADD_INSN(ret, nd_line(node), nop);
3296 ADD_INSN(ret, nd_line(node), leave);
3297 ADD_LABEL(ret, label_miss);
3298 resq = resq->nd_head;
3300 break;
3302 case NODE_ENSURE:{
3303 DECL_ANCHOR(ensr);
3304 VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
3305 rb_str_concat(rb_str_new2
3306 ("ensure in "),
3307 iseq->name),
3308 ISEQ_TYPE_ENSURE);
3309 LABEL *lstart = NEW_LABEL(nd_line(node));
3310 LABEL *lend = NEW_LABEL(nd_line(node));
3311 LABEL *lcont = NEW_LABEL(nd_line(node));
3312 struct ensure_range er = { 0 };
3313 struct iseq_compile_data_ensure_node_stack enl;
3314 struct ensure_range *erange;
3316 INIT_ANCHOR(ensr);
3317 er.begin = lstart;
3318 er.end = lend;
3319 enl.ensure_node = node->nd_ensr;
3320 enl.prev = iseq->compile_data->ensure_node_stack; /* prev */
3321 enl.erange = &er;
3322 COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
3324 iseq->compile_data->ensure_node_stack = &enl;
3326 ADD_LABEL(ret, lstart);
3327 COMPILE_(ret, "ensure head", node->nd_head, poped);
3328 ADD_LABEL(ret, lend);
3329 if (ensr->anchor.next == 0) {
3330 ADD_INSN(ret, nd_line(node), nop);
3332 else {
3333 ADD_SEQ(ret, ensr);
3335 ADD_LABEL(ret, lcont);
3337 erange = iseq->compile_data->ensure_node_stack->erange;
3338 while (erange) {
3339 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
3340 ensure, lcont);
3341 erange = erange->next;
3343 iseq->compile_data->ensure_node_stack = enl.prev;
3344 break;
3347 case NODE_AND:
3348 case NODE_OR:{
3349 LABEL *end_label = NEW_LABEL(nd_line(node));
3350 COMPILE(ret, "nd_1st", node->nd_1st);
3351 if (!poped) {
3352 ADD_INSN(ret, nd_line(node), dup);
3354 if (type == NODE_AND) {
3355 ADD_INSNL(ret, nd_line(node), branchunless, end_label);
3357 else {
3358 ADD_INSNL(ret, nd_line(node), branchif, end_label);
3360 if (!poped) {
3361 ADD_INSN(ret, nd_line(node), pop);
3363 COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
3364 ADD_LABEL(ret, end_label);
3365 break;
3368 case NODE_MASGN:{
3369 compile_massign(iseq, ret, node, poped);
3370 break;
3373 case NODE_LASGN:{
3374 ID id = node->nd_vid;
3375 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3377 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
3378 COMPILE(ret, "rvalue", node->nd_value);
3380 if (!poped) {
3381 ADD_INSN(ret, nd_line(node), dup);
3383 ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx));
3385 break;
3387 case NODE_DASGN:
3388 case NODE_DASGN_CURR:{
3389 int idx, lv, ls;
3390 COMPILE(ret, "dvalue", node->nd_value);
3391 debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
3393 if (!poped) {
3394 ADD_INSN(ret, nd_line(node), dup);
3397 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
3399 if (idx < 0) {
3400 rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
3403 ADD_INSN2(ret, nd_line(node), setdynamic,
3404 INT2FIX(ls - idx), INT2FIX(lv));
3405 break;
3407 case NODE_GASGN:{
3408 COMPILE(ret, "lvalue", node->nd_value);
3410 if (!poped) {
3411 ADD_INSN(ret, nd_line(node), dup);
3413 ADD_INSN1(ret, nd_line(node), setglobal,
3414 (((long)node->nd_entry) | 1));
3415 break;
3417 case NODE_IASGN:
3418 case NODE_IASGN2:{
3419 COMPILE(ret, "lvalue", node->nd_value);
3420 if (!poped) {
3421 ADD_INSN(ret, nd_line(node), dup);
3423 ADD_INSN1(ret, nd_line(node), setinstancevariable,
3424 ID2SYM(node->nd_vid));
3425 break;
3427 case NODE_CDECL:{
3428 COMPILE(ret, "lvalue", node->nd_value);
3430 if (!poped) {
3431 ADD_INSN(ret, nd_line(node), dup);
3434 if (node->nd_vid) {
3435 ADD_INSN(ret, nd_line(node), putnil);
3436 ADD_INSN1(ret, nd_line(node), setconstant,
3437 ID2SYM(node->nd_vid));
3439 else {
3440 compile_cpath(ret, iseq, node->nd_else);
3441 ADD_INSN1(ret, nd_line(node), setconstant,
3442 ID2SYM(node->nd_else->nd_mid));
3444 break;
3446 case NODE_CVASGN:{
3447 COMPILE(ret, "cvasgn val", node->nd_value);
3448 if (!poped) {
3449 ADD_INSN(ret, nd_line(node), dup);
3451 ADD_INSN1(ret, nd_line(node), setclassvariable,
3452 ID2SYM(node->nd_vid));
3453 break;
3455 case NODE_OP_ASGN1: {
3456 DECL_ANCHOR(args);
3457 VALUE argc;
3458 unsigned long flag = 0;
3459 ID id = node->nd_mid;
3462 * a[x] (op)= y
3464 * eval a # a
3465 * eval x # a x
3466 * dupn 2 # a x a x
3467 * send :[] # a x a[x]
3468 * eval y # a x a[x] y
3469 * send op # a x a[x]+y
3470 * send []= # ret
3474 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
3475 * NODE_OP_ASGN nd_recv
3476 * nd_args->nd_head
3477 * nd_args->nd_body
3478 * nd_mid
3481 COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
3482 if (nd_type(node->nd_args->nd_body) != NODE_ZARRAY) {
3483 INIT_ANCHOR(args);
3484 argc = setup_args(iseq, args, node->nd_args->nd_body, &flag);
3485 ADD_SEQ(ret, args);
3487 else {
3488 argc = INT2FIX(0);
3490 ADD_INSN1(ret, nd_line(node), dupn, INT2FIX(FIX2INT(argc)+1));
3491 ADD_SEND_R(ret, nd_line(node), ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
3493 if (id == 0 || id == 1) {
3494 /* 0: or, 1: and
3495 a[x] ||= y
3497 unless/if a[x]
3498 a[x]= y
3499 else
3503 LABEL *label = NEW_LABEL(nd_line(node));
3504 LABEL *lfin = NEW_LABEL(nd_line(node));
3506 if (id == 0) {
3507 /* or */
3508 ADD_INSN(ret, nd_line(node), dup);
3509 ADD_INSNL(ret, nd_line(node), branchif, label);
3510 ADD_INSN(ret, nd_line(node), pop);
3512 else {
3513 /* and */
3514 ADD_INSNL(ret, nd_line(node), branchunless, label);
3517 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3518 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3519 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3520 ADD_INSN(ret, nd_line(node), concatarray);
3521 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3522 argc, Qfalse, LONG2FIX(flag));
3524 else {
3525 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3526 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3528 ADD_INSNL(ret, nd_line(node), jump, lfin);
3529 ADD_LABEL(ret, label);
3530 if (id == 0) { /* or */
3531 ADD_INSN(ret, nd_line(node), swap);
3532 ADD_INSN(ret, nd_line(node), pop);
3533 ADD_INSN(ret, nd_line(node), swap);
3534 ADD_INSN(ret, nd_line(node), pop);
3536 else if (id == 1) { /* and */
3537 ADD_INSN(ret, nd_line(node), pop);
3538 ADD_INSN(ret, nd_line(node), pop);
3539 ADD_INSN(ret, nd_line(node), putnil);
3541 ADD_LABEL(ret, lfin);
3543 else {
3544 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3545 ADD_SEND(ret, nd_line(node), ID2SYM(id), INT2FIX(1));
3546 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3547 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3548 ADD_INSN(ret, nd_line(node), concatarray);
3549 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3550 argc, Qfalse, LONG2FIX(flag));
3552 else {
3553 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3554 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3558 if (poped) {
3559 ADD_INSN(ret, nd_line(node), pop);
3562 break;
3564 case NODE_OP_ASGN2:{
3565 ID atype = node->nd_next->nd_mid;
3566 LABEL *lfin = NEW_LABEL(nd_line(node));
3567 LABEL *lcfin = NEW_LABEL(nd_line(node));
3569 class C; attr_accessor :c; end
3570 r = C.new
3571 r.a &&= v # asgn2
3573 eval r # r
3574 dup # r r
3575 eval r.a # r o
3577 # or
3578 dup # r o o
3579 if lcfin # r o
3580 pop # r
3581 eval v # r v
3582 send a= # v
3583 jump lfin # v
3585 lcfin: # r o
3586 swap # o r
3587 pop # o
3589 lfin: # v
3591 # and
3592 dup # r o o
3593 unless lcfin
3594 pop # r
3595 eval v # r v
3596 send a= # v
3597 jump lfin # v
3599 # others
3600 eval v # r o v
3601 send ?? # r w
3602 send a= # w
3606 COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
3607 ADD_INSN(ret, nd_line(node), dup);
3608 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_vid),
3609 INT2FIX(0));
3611 if (atype == 0 || atype == 1) { /* 0: OR or 1: AND */
3612 ADD_INSN(ret, nd_line(node), dup);
3613 if (atype == 0) {
3614 ADD_INSNL(ret, nd_line(node), branchif, lcfin);
3616 else {
3617 ADD_INSNL(ret, nd_line(node), branchunless, lcfin);
3619 ADD_INSN(ret, nd_line(node), pop);
3620 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3621 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3622 INT2FIX(1));
3623 ADD_INSNL(ret, nd_line(node), jump, lfin);
3625 ADD_LABEL(ret, lcfin);
3626 ADD_INSN(ret, nd_line(node), swap);
3627 ADD_INSN(ret, nd_line(node), pop);
3629 ADD_LABEL(ret, lfin);
3631 else {
3632 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3633 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_mid),
3634 INT2FIX(1));
3635 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3636 INT2FIX(1));
3639 if (poped) {
3640 /* we can apply more optimize */
3641 ADD_INSN(ret, nd_line(node), pop);
3643 break;
3645 case NODE_OP_ASGN_AND:
3646 case NODE_OP_ASGN_OR:{
3647 LABEL *lfin = NEW_LABEL(nd_line(node));
3648 LABEL *lassign;
3650 if (nd_type(node) == NODE_OP_ASGN_OR) {
3651 LABEL *lfinish[2];
3652 lfinish[0] = lfin;
3653 lfinish[1] = 0;
3654 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
3655 lassign = lfinish[1];
3656 if (!lassign) {
3657 lassign = NEW_LABEL(nd_line(node));
3659 ADD_INSNL(ret, nd_line(node), branchunless, lassign);
3661 else {
3662 lassign = NEW_LABEL(nd_line(node));
3665 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
3666 ADD_INSN(ret, nd_line(node), dup);
3668 if (nd_type(node) == NODE_OP_ASGN_AND) {
3669 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
3671 else {
3672 ADD_INSNL(ret, nd_line(node), branchif, lfin);
3675 ADD_INSN(ret, nd_line(node), pop);
3676 ADD_LABEL(ret, lassign);
3677 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
3678 ADD_LABEL(ret, lfin);
3680 if (poped) {
3681 /* we can apply more optimize */
3682 ADD_INSN(ret, nd_line(node), pop);
3684 break;
3686 case NODE_CALL:
3687 case NODE_FCALL:
3688 case NODE_VCALL:{ /* VCALL: variable or call */
3690 call: obj.method(...)
3691 fcall: func(...)
3692 vcall: func
3694 DECL_ANCHOR(recv);
3695 DECL_ANCHOR(args);
3696 ID mid = node->nd_mid;
3697 VALUE argc;
3698 unsigned long flag = 0;
3699 VALUE parent_block = iseq->compile_data->current_block;
3700 iseq->compile_data->current_block = Qfalse;
3702 INIT_ANCHOR(recv);
3703 INIT_ANCHOR(args);
3704 #if SUPPORT_JOKE
3705 if (nd_type(node) == NODE_VCALL) {
3706 if (mid == idBitblt) {
3707 ADD_INSN(ret, nd_line(node), bitblt);
3708 break;
3710 else if (mid == idAnswer) {
3711 ADD_INSN(ret, nd_line(node), answer);
3712 break;
3715 /* only joke */
3717 static ID goto_id;
3718 static ID label_id;
3719 VALUE label;
3720 VALUE label_sym;
3722 if (goto_id == 0) {
3723 goto_id = rb_intern("__goto__");
3724 label_id = rb_intern("__label__");
3727 if (nd_type(node) == NODE_FCALL &&
3728 (mid == goto_id || mid == label_id)) {
3729 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
3730 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
3732 label_sym = label = node->nd_args->nd_head->nd_lit;
3733 if ((label =
3734 rb_hash_aref(iseq->compile_data,
3735 label_sym)) == Qnil) {
3736 rb_hash_aset(iseq->compile_data, label_sym,
3737 label = NEW_LABEL(nd_line(node)));
3740 else {
3741 rb_bug("invalid goto/label format");
3745 if (mid == goto_id) {
3746 ADD_INSNL(ret, nd_line(node), jump, label);
3748 else {
3749 ADD_LABEL(ret, label);
3751 break;
3754 #endif
3755 /* reciever */
3756 if (type == NODE_CALL) {
3757 COMPILE(recv, "recv", node->nd_recv);
3759 else if (type == NODE_FCALL || type == NODE_VCALL) {
3760 ADD_CALL_RECEIVER(recv, nd_line(node));
3763 /* args */
3764 if (nd_type(node) != NODE_VCALL) {
3765 argc = setup_args(iseq, args, node->nd_args, &flag);
3767 else {
3768 argc = INT2FIX(0);
3771 ADD_SEQ(ret, recv);
3772 ADD_SEQ(ret, args);
3774 debugp_param("call args argc", argc);
3775 debugp_param("call method", ID2SYM(mid));
3777 switch (nd_type(node)) {
3778 case NODE_VCALL:
3779 flag |= VM_CALL_VCALL_BIT;
3780 /* VCALL is funcall, so fall through */
3781 case NODE_FCALL:
3782 flag |= VM_CALL_FCALL_BIT;
3785 ADD_SEND_R(ret, nd_line(node), ID2SYM(mid),
3786 argc, parent_block, LONG2FIX(flag));
3788 if (poped) {
3789 ADD_INSN(ret, nd_line(node), pop);
3791 break;
3793 case NODE_SUPER:
3794 case NODE_ZSUPER:{
3795 DECL_ANCHOR(args);
3796 VALUE argc;
3797 unsigned long flag = 0;
3798 VALUE parent_block = iseq->compile_data->current_block;
3800 INIT_ANCHOR(args);
3801 iseq->compile_data->current_block = Qfalse;
3802 if (nd_type(node) == NODE_SUPER) {
3803 argc = setup_args(iseq, args, node->nd_args, &flag);
3805 else {
3806 /* NODE_ZSUPER */
3807 int i;
3808 rb_iseq_t *liseq = iseq->local_iseq;
3810 argc = INT2FIX(liseq->argc);
3812 /* normal arguments */
3813 for (i = 0; i < liseq->argc; i++) {
3814 int idx = liseq->local_size - i;
3815 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3818 if (!liseq->arg_simple) {
3819 if (liseq->arg_opts) {
3820 /* optional arguments */
3821 int j;
3822 for (j = 0; j < liseq->arg_opts - 1; j++) {
3823 int idx = liseq->local_size - (i + j);
3824 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3826 i += j;
3827 argc = INT2FIX(i);
3830 if (liseq->arg_rest != -1) {
3831 /* rest argument */
3832 int idx = liseq->local_size - liseq->arg_rest;
3833 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3834 argc = INT2FIX(liseq->arg_rest + 1);
3835 flag |= VM_CALL_ARGS_SPLAT_BIT;
3838 if (liseq->arg_post_len) {
3839 /* post arguments */
3840 int post_len = liseq->arg_post_len;
3841 int post_start = liseq->arg_post_start;
3843 if (liseq->arg_rest != -1) {
3844 int j;
3845 for (j=0; j<post_len; j++) {
3846 int idx = liseq->local_size - (post_start + j);
3847 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3849 ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j));
3850 ADD_INSN (args, nd_line(node), concatarray);
3851 /* argc is setteled at above */
3853 else {
3854 int j;
3855 for (j=0; j<post_len; j++) {
3856 int idx = liseq->local_size - (post_start + j);
3857 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3859 argc = INT2FIX(post_len + post_start);
3865 /* dummy reciever */
3866 ADD_INSN1(ret, nd_line(node), putobject,
3867 nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
3868 ADD_SEQ(ret, args);
3869 ADD_INSN3(ret, nd_line(node), invokesuper,
3870 argc, parent_block, LONG2FIX(flag));
3872 if (poped) {
3873 ADD_INSN(ret, nd_line(node), pop);
3875 break;
3877 case NODE_ARRAY:{
3878 compile_array_(iseq, ret, node, Qtrue, poped);
3879 break;
3881 case NODE_ZARRAY:{
3882 if (!poped) {
3883 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(0));
3885 break;
3887 case NODE_VALUES:{
3888 NODE *n = node;
3889 while (n) {
3890 COMPILE(ret, "values item", n->nd_head);
3891 n = n->nd_next;
3893 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(node->nd_alen));
3894 if (poped) {
3895 ADD_INSN(ret, nd_line(node), pop);
3897 break;
3899 case NODE_HASH:{
3900 DECL_ANCHOR(list);
3901 VALUE size = 0;
3902 int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
3904 INIT_ANCHOR(list);
3905 switch (type) {
3906 case NODE_ARRAY:{
3907 compile_array(iseq, list, node->nd_head, Qfalse);
3908 size = OPERAND_AT(POP_ELEMENT(list), 0);
3909 ADD_SEQ(ret, list);
3910 break;
3912 case NODE_ZARRAY:
3913 size = INT2FIX(0);
3914 break;
3916 default:
3917 rb_bug("can't make hash with this node: %s", ruby_node_name(type));
3920 ADD_INSN1(ret, nd_line(node), newhash, size);
3922 if (poped) {
3923 ADD_INSN(ret, nd_line(node), pop);
3925 break;
3927 case NODE_RETURN:{
3928 rb_iseq_t *is = iseq;
3930 while (is) {
3931 if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) {
3932 COMPILE_ERROR((ERROR_ARGS "Invalid return"));
3933 break;
3935 else {
3936 LABEL *splabel = 0;
3938 if (is->type == ISEQ_TYPE_METHOD) {
3939 splabel = NEW_LABEL(0);
3940 ADD_LABEL(ret, splabel);
3941 ADD_ADJUST(ret, nd_line(node), 0);
3944 COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
3946 if (is->type == ISEQ_TYPE_METHOD) {
3947 add_ensure_iseq(ret, iseq);
3948 ADD_INSN(ret, nd_line(node), leave);
3949 ADD_ADJUST_RESTORE(ret, splabel);
3951 if (!poped) {
3952 ADD_INSN(ret, nd_line(node), putnil);
3955 else {
3956 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x01) /* TAG_RETURN */ );
3957 if (poped) {
3958 ADD_INSN(ret, nd_line(node), pop);
3961 break;
3964 break;
3966 case NODE_YIELD:{
3967 DECL_ANCHOR(args);
3968 VALUE argc;
3969 unsigned long flag = 0;
3971 INIT_ANCHOR(args);
3972 if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) {
3973 COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
3976 if (node->nd_head) {
3977 argc = setup_args(iseq, args, node->nd_head, &flag);
3979 else {
3980 argc = INT2FIX(0);
3983 ADD_SEQ(ret, args);
3984 ADD_INSN2(ret, nd_line(node), invokeblock, argc, LONG2FIX(flag));
3986 if (poped) {
3987 ADD_INSN(ret, nd_line(node), pop);
3989 break;
3991 case NODE_LVAR:{
3992 if (!poped) {
3993 ID id = node->nd_vid;
3994 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3996 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
3997 ADD_INSN1(ret, nd_line(node), getlocal, INT2FIX(idx));
3999 break;
4001 case NODE_DVAR:{
4002 int lv, idx, ls;
4003 debugi("nd_vid", node->nd_vid);
4004 if (!poped) {
4005 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
4006 if (idx < 0) {
4007 rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
4009 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(ls - idx),
4010 INT2FIX(lv));
4012 break;
4014 case NODE_GVAR:{
4015 ADD_INSN1(ret, nd_line(node), getglobal,
4016 (((long)node->nd_entry) | 1));
4017 if (poped) {
4018 ADD_INSN(ret, nd_line(node), pop);
4020 break;
4022 case NODE_IVAR:{
4023 debugi("nd_vid", node->nd_vid);
4024 if (!poped) {
4025 ADD_INSN1(ret, nd_line(node), getinstancevariable,
4026 ID2SYM(node->nd_vid));
4028 break;
4030 case NODE_CONST:{
4031 debugi("nd_vid", node->nd_vid);
4033 if (iseq->compile_data->option->inline_const_cache) {
4034 LABEL *lstart = NEW_LABEL(nd_line(node));
4035 LABEL *lend = NEW_LABEL(nd_line(node));
4037 ADD_LABEL(ret, lstart);
4038 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4039 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4040 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4041 ADD_LABEL(ret, lend);
4043 else {
4044 ADD_INSN(ret, nd_line(node), putnil);
4045 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4048 if (poped) {
4049 ADD_INSN(ret, nd_line(node), pop);
4051 break;
4053 case NODE_CVAR:{
4054 if (!poped) {
4055 ADD_INSN1(ret, nd_line(node), getclassvariable,
4056 ID2SYM(node->nd_vid));
4058 break;
4060 case NODE_NTH_REF:{
4061 if (!poped) {
4062 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4063 INT2FIX(node->nd_nth << 1));
4065 break;
4067 case NODE_BACK_REF:{
4068 if (!poped) {
4069 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4070 INT2FIX(0x01 | (node->nd_nth << 1)));
4072 break;
4074 case NODE_MATCH:
4075 case NODE_MATCH2:
4076 case NODE_MATCH3:{
4077 DECL_ANCHOR(recv);
4078 DECL_ANCHOR(val);
4080 INIT_ANCHOR(recv);
4081 INIT_ANCHOR(val);
4082 switch(nd_type(node)) {
4083 case NODE_MATCH:
4084 ADD_INSN1(recv, nd_line(node), putobject, node->nd_lit);
4085 ADD_INSN2(val, nd_line(node), getspecial, INT2FIX(0),
4086 INT2FIX(0));
4087 break;
4088 case NODE_MATCH2:
4089 COMPILE(recv, "reciever", node->nd_recv);
4090 COMPILE(val, "value", node->nd_value);
4091 break;
4092 case NODE_MATCH3:
4093 COMPILE(recv, "reciever", node->nd_value);
4094 COMPILE(val, "value", node->nd_recv);
4095 break;
4098 if (iseq->compile_data->option->specialized_instruction) {
4099 /* TODO: detect by node */
4100 if (recv->last == recv->anchor.next &&
4101 INSN_OF(recv->last) == BIN(putobject) &&
4102 nd_type(node) == NODE_MATCH2) {
4103 ADD_SEQ(ret, val);
4104 ADD_INSN1(ret, nd_line(node), opt_regexpmatch1,
4105 OPERAND_AT(recv->last, 0));
4107 else {
4108 ADD_SEQ(ret, recv);
4109 ADD_SEQ(ret, val);
4110 ADD_INSN(ret, nd_line(node), opt_regexpmatch2);
4113 else {
4114 ADD_SEQ(ret, recv);
4115 ADD_SEQ(ret, val);
4116 ADD_SEND(ret, nd_line(node), ID2SYM(idEqTilde), INT2FIX(1));
4119 if (poped) {
4120 ADD_INSN(ret, nd_line(node), pop);
4122 break;
4124 case NODE_LIT:{
4125 debugp_param("lit", node->nd_lit);
4126 if (!poped) {
4127 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4129 break;
4131 case NODE_STR:{
4132 debugp_param("nd_lit", node->nd_lit);
4133 if (!poped) {
4134 ADD_INSN1(ret, nd_line(node), putstring, node->nd_lit);
4136 break;
4138 case NODE_DSTR:{
4139 compile_dstr(iseq, ret, node);
4141 if (poped) {
4142 ADD_INSN(ret, nd_line(node), pop);
4144 break;
4146 case NODE_XSTR:{
4147 ADD_CALL_RECEIVER(ret, nd_line(node));
4148 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4149 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4151 if (poped) {
4152 ADD_INSN(ret, nd_line(node), pop);
4154 break;
4156 case NODE_DXSTR:{
4157 ADD_CALL_RECEIVER(ret, nd_line(node));
4158 compile_dstr(iseq, ret, node);
4159 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4161 if (poped) {
4162 ADD_INSN(ret, nd_line(node), pop);
4164 break;
4166 case NODE_EVSTR:{
4167 COMPILE(ret, "nd_body", node->nd_body);
4169 if (poped) {
4170 ADD_INSN(ret, nd_line(node), pop);
4172 else {
4173 ADD_INSN(ret, nd_line(node), tostring);
4175 break;
4177 case NODE_DREGX:{
4178 compile_dregx(iseq, ret, node);
4180 if (poped) {
4181 ADD_INSN(ret, nd_line(node), pop);
4183 break;
4185 case NODE_DREGX_ONCE:{
4186 /* TODO: once? */
4187 LABEL *lstart = NEW_LABEL(nd_line(node));
4188 LABEL *lend = NEW_LABEL(nd_line(node));
4190 ADD_LABEL(ret, lstart);
4191 ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend);
4192 ADD_INSN(ret, nd_line(node), pop);
4194 compile_dregx(iseq, ret, node);
4196 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4197 ADD_LABEL(ret, lend);
4199 if (poped) {
4200 ADD_INSN(ret, nd_line(node), pop);
4202 break;
4204 case NODE_ARGSCAT:{
4205 COMPILE(ret, "argscat head", node->nd_head);
4206 COMPILE(ret, "argscat body", node->nd_body);
4207 ADD_INSN(ret, nd_line(node), concatarray);
4208 break;
4210 case NODE_ARGSPUSH:{
4211 COMPILE(ret, "arsgpush head", node->nd_head);
4212 COMPILE(ret, "argspush body", node->nd_body);
4213 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
4214 ADD_INSN(ret, nd_line(node), concatarray);
4215 break;
4217 case NODE_SPLAT:{
4218 COMPILE(ret, "splat", node->nd_head);
4219 ADD_INSN1(ret, nd_line(node), splatarray, Qfalse);
4221 if (poped) {
4222 ADD_INSN(ret, nd_line(node), pop);
4224 break;
4226 case NODE_DEFN:{
4227 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4228 rb_str_dup(rb_id2str(node->nd_mid)),
4229 ISEQ_TYPE_METHOD);
4231 debugp_param("defn/iseq", iseqval);
4233 ADD_INSN (ret, nd_line(node), putnil);
4234 ADD_INSN3(ret, nd_line(node), definemethod,
4235 ID2SYM(node->nd_mid), iseqval, INT2FIX(0));
4236 if (!poped) {
4237 ADD_INSN(ret, nd_line(node), putnil);
4239 debugp_param("defn", iseqval);
4240 break;
4242 case NODE_DEFS:{
4243 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4244 rb_str_dup(rb_id2str(node->nd_mid)),
4245 ISEQ_TYPE_METHOD);
4247 debugp_param("defs/iseq", iseqval);
4249 COMPILE(ret, "defs: recv", node->nd_recv);
4250 ADD_INSN3(ret, nd_line(node), definemethod,
4251 ID2SYM(node->nd_mid), iseqval, INT2FIX(1));
4252 if (!poped) {
4253 ADD_INSN(ret, nd_line(node), putnil);
4255 break;
4257 case NODE_ALIAS:{
4258 COMPILE(ret, "alias arg1", node->u1.node);
4259 COMPILE(ret, "alias arg2", node->u2.node);
4261 ADD_INSN1(ret, nd_line(node), alias, Qfalse);
4263 if (!poped) {
4264 ADD_INSN(ret, nd_line(node), putnil);
4266 break;
4268 case NODE_VALIAS:{
4269 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id));
4270 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id));
4271 ADD_INSN1(ret, nd_line(node), alias, Qtrue);
4273 if (!poped) {
4274 ADD_INSN(ret, nd_line(node), putnil);
4276 break;
4278 case NODE_UNDEF:{
4279 COMPILE(ret, "undef arg", node->u2.node);
4280 ADD_INSN(ret, nd_line(node), undef);
4282 if (!poped) {
4283 ADD_INSN(ret, nd_line(node), putnil);
4285 break;
4287 case NODE_CLASS:{
4288 VALUE iseqval =
4289 NEW_CHILD_ISEQVAL(
4290 node->nd_body,
4291 rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4292 ISEQ_TYPE_CLASS);
4293 compile_cpath(ret, iseq, node->nd_cpath);
4294 COMPILE(ret, "super", node->nd_super);
4295 ADD_INSN3(ret, nd_line(node), defineclass,
4296 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(0));
4298 if (poped) {
4299 ADD_INSN(ret, nd_line(node), pop);
4301 break;
4303 case NODE_MODULE:{
4304 VALUE iseqval = NEW_CHILD_ISEQVAL(
4305 node->nd_body,
4306 rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4307 ISEQ_TYPE_CLASS);
4309 COMPILE(ret, "mbase", node->nd_cpath->nd_head);
4310 ADD_INSN (ret, nd_line(node), putnil); /* dummy */
4311 ADD_INSN3(ret, nd_line(node), defineclass,
4312 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2));
4313 if (poped) {
4314 ADD_INSN(ret, nd_line(node), pop);
4316 break;
4318 case NODE_SCLASS:{
4319 VALUE iseqval =
4320 NEW_ISEQVAL(node->nd_body, rb_str_new2("singletonclass"),
4321 ISEQ_TYPE_CLASS);
4323 COMPILE(ret, "sclass#recv", node->nd_recv);
4324 ADD_INSN (ret, nd_line(node), putnil);
4325 ADD_INSN3(ret, nd_line(node), defineclass,
4326 ID2SYM(rb_intern("singletonclass")), iseqval, INT2FIX(1));
4328 if (poped) {
4329 ADD_INSN(ret, nd_line(node), pop);
4331 break;
4333 case NODE_COLON2:{
4334 if (rb_is_const_id(node->nd_mid)) {
4335 /* constant */
4336 LABEL *lstart = NEW_LABEL(nd_line(node));
4337 LABEL *lend = NEW_LABEL(nd_line(node));
4338 DECL_ANCHOR(pref);
4339 DECL_ANCHOR(body);
4341 INIT_ANCHOR(pref);
4342 INIT_ANCHOR(body);
4343 compile_colon2(iseq, node, pref, body);
4344 if (LIST_SIZE_ZERO(pref)) {
4345 if (iseq->compile_data->option->inline_const_cache) {
4346 ADD_LABEL(ret, lstart);
4347 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4349 else {
4350 ADD_INSN(ret, nd_line(node), putnil);
4353 ADD_SEQ(ret, body);
4355 if (iseq->compile_data->option->inline_const_cache) {
4356 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4357 ADD_LABEL(ret, lend);
4360 else {
4361 ADD_SEQ(ret, pref);
4362 ADD_SEQ(ret, body);
4365 else {
4366 /* function call */
4367 ADD_CALL_RECEIVER(ret, nd_line(node));
4368 COMPILE(ret, "colon2#nd_head", node->nd_head);
4369 ADD_CALL(ret, nd_line(node), ID2SYM(node->nd_mid),
4370 INT2FIX(1));
4372 if (poped) {
4373 ADD_INSN(ret, nd_line(node), pop);
4375 break;
4377 case NODE_COLON3:{
4378 LABEL *lstart = NEW_LABEL(nd_line(node));
4379 LABEL *lend = NEW_LABEL(nd_line(node));
4380 debugi("colon3#nd_mid", node->nd_mid);
4382 /* add cache insn */
4383 if (iseq->compile_data->option->inline_const_cache) {
4384 ADD_LABEL(ret, lstart);
4385 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4386 ADD_INSN(ret, nd_line(node), pop);
4389 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
4390 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4392 if (iseq->compile_data->option->inline_const_cache) {
4393 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4394 ADD_LABEL(ret, lend);
4397 if (poped) {
4398 ADD_INSN(ret, nd_line(node), pop);
4400 break;
4402 case NODE_DOT2:
4403 case NODE_DOT3:{
4404 int flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
4405 COMPILE(ret, "min", (NODE *) node->nd_beg);
4406 COMPILE(ret, "max", (NODE *) node->nd_end);
4407 if (poped) {
4408 ADD_INSN(ret, nd_line(node), pop);
4409 ADD_INSN(ret, nd_line(node), pop);
4411 else {
4412 ADD_INSN1(ret, nd_line(node), newrange, flag);
4414 break;
4416 case NODE_FLIP2:
4417 case NODE_FLIP3:{
4418 LABEL *lend = NEW_LABEL(nd_line(node));
4419 LABEL *lfin = NEW_LABEL(nd_line(node));
4420 LABEL *ltrue = NEW_LABEL(nd_line(node));
4421 VALUE key = rb_sprintf("flipflag/%s-%p-%d",
4422 RSTRING_PTR(iseq->name), iseq,
4423 iseq->compile_data->flip_cnt++);
4425 iseq_add_mark_object_compile_time(iseq, key);
4426 ADD_INSN2(ret, nd_line(node), getspecial, key, INT2FIX(0));
4427 ADD_INSNL(ret, nd_line(node), branchif, lend);
4429 /* *flip == 0 */
4430 COMPILE(ret, "flip2 beg", node->nd_beg);
4431 ADD_INSN(ret, nd_line(node), dup);
4432 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
4433 if (nd_type(node) == NODE_FLIP3) {
4434 ADD_INSN(ret, nd_line(node), dup);
4435 ADD_INSN1(ret, nd_line(node), setspecial, key);
4436 ADD_INSNL(ret, nd_line(node), jump, lfin);
4438 else {
4439 ADD_INSN1(ret, nd_line(node), setspecial, key);
4442 /* *flip == 1 */
4443 ADD_LABEL(ret, lend);
4444 COMPILE(ret, "flip2 end", node->nd_end);
4445 ADD_INSNL(ret, nd_line(node), branchunless, ltrue);
4446 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4447 ADD_INSN1(ret, nd_line(node), setspecial, key);
4449 ADD_LABEL(ret, ltrue);
4450 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4452 ADD_LABEL(ret, lfin);
4453 break;
4455 case NODE_SELF:{
4456 if (!poped) {
4457 ADD_INSN(ret, nd_line(node), putself);
4459 break;
4461 case NODE_NIL:{
4462 if (!poped) {
4463 ADD_INSN(ret, nd_line(node), putnil);
4465 break;
4467 case NODE_TRUE:{
4468 if (!poped) {
4469 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4471 break;
4473 case NODE_FALSE:{
4474 if (!poped) {
4475 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4477 break;
4479 case NODE_ERRINFO:{
4480 if (!poped) {
4481 if (iseq->type == ISEQ_TYPE_RESCUE) {
4482 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
4483 INT2FIX(0));
4485 else {
4486 rb_iseq_t *ip = iseq;
4487 int level = 0;
4488 while (ip) {
4489 if (ip->type == ISEQ_TYPE_RESCUE) {
4490 break;
4492 ip = ip->parent_iseq;
4493 level++;
4495 if (ip) {
4496 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
4497 INT2FIX(level));
4499 else {
4500 ADD_INSN(ret, nd_line(node), putnil);
4504 break;
4506 case NODE_DEFINED:{
4507 if (!poped) {
4508 LABEL *lfinish[2];
4509 lfinish[0] = NEW_LABEL(nd_line(node));
4510 lfinish[1] = 0;
4511 defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
4512 if (lfinish[1]) {
4513 ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
4514 ADD_LABEL(ret, lfinish[1]);
4515 ADD_INSN(ret, nd_line(node), putnil);
4517 ADD_LABEL(ret, lfinish[0]);
4519 break;
4521 case NODE_POSTEXE:{
4522 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4523 ADD_INSN1(ret, nd_line(node), postexe, block);
4524 if (!poped) {
4525 ADD_INSN(ret, nd_line(node), putnil);
4527 break;
4529 case NODE_DSYM:{
4530 compile_dstr(iseq, ret, node);
4531 if (!poped) {
4532 ADD_SEND(ret, nd_line(node), ID2SYM(idIntern), INT2FIX(0));
4534 else {
4535 ADD_INSN(ret, nd_line(node), pop);
4537 break;
4539 case NODE_ATTRASGN:{
4540 DECL_ANCHOR(recv);
4541 DECL_ANCHOR(args);
4542 unsigned long flag = 0;
4543 VALUE argc;
4545 INIT_ANCHOR(recv);
4546 INIT_ANCHOR(args);
4547 argc = setup_args(iseq, args, node->nd_args, &flag);
4549 if (node->nd_recv == (NODE *) 1) {
4550 flag |= VM_CALL_FCALL_BIT;
4551 ADD_INSN(recv, nd_line(node), putself);
4553 else {
4554 COMPILE(recv, "recv", node->nd_recv);
4557 debugp_param("argc", argc);
4558 debugp_param("nd_mid", ID2SYM(node->nd_mid));
4560 if (!poped) {
4561 ADD_INSN(ret, nd_line(node), putnil);
4562 ADD_SEQ(ret, recv);
4563 ADD_SEQ(ret, args);
4565 if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
4566 ADD_INSN1(ret, nd_line(node), topn, INT2FIX(1));
4567 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 3));
4568 ADD_INSN (ret, nd_line(node), pop);
4570 else {
4571 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 1));
4574 else {
4575 ADD_SEQ(ret, recv);
4576 ADD_SEQ(ret, args);
4578 ADD_SEND_R(ret, nd_line(node), ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
4579 ADD_INSN(ret, nd_line(node), pop);
4581 break;
4583 case NODE_OPTBLOCK:{
4584 /* for optimize */
4585 LABEL *redo_label = NEW_LABEL(0);
4586 LABEL *next_label = NEW_LABEL(0);
4588 iseq->compile_data->start_label = next_label;
4589 iseq->compile_data->redo_label = redo_label;
4591 ADD_LABEL(ret, redo_label);
4592 COMPILE_(ret, "optblock body", node->nd_head, 1 /* pop */ );
4593 ADD_LABEL(ret, next_label);
4594 ADD_INSN(ret, 0, opt_checkenv);
4595 break;
4597 case NODE_PRELUDE:{
4598 COMPILE_POPED(ret, "prelude", node->nd_head);
4599 COMPILE_(ret, "body", node->nd_body, poped);
4600 break;
4602 case NODE_LAMBDA:{
4603 /* compile same as lambda{...} */
4604 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4605 VALUE argc = INT2FIX(0);
4606 ADD_CALL_RECEIVER(ret, nd_line(node));
4607 ADD_CALL_WITH_BLOCK(ret, nd_line(node), ID2SYM(idLambda), argc, block);
4609 if (poped) {
4610 ADD_INSN(ret, nd_line(node), pop);
4612 break;
4614 default:
4615 rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
4616 return Qnil;
4619 debug_node_end();
4620 return COMPILE_OK;
4623 /***************************/
4624 /* instruction information */
4625 /***************************/
4627 static int
4628 insn_data_length(INSN *iobj)
4630 return insn_len(iobj->insn_id);
4633 static int
4634 calc_sp_depth(int depth, INSN *insn)
4636 return insn_stack_increase(depth, insn->insn_id, insn->operands);
4639 static int
4640 insn_data_line_no(INSN *iobj)
4642 return insn_len(iobj->line_no);
4645 static VALUE
4646 insn_data_to_s_detail(INSN *iobj)
4648 VALUE str = rb_str_new(0, 0);
4650 str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
4651 if (iobj->operands) {
4652 const char *types = insn_op_types(iobj->insn_id);
4653 int j;
4655 for (j = 0; types[j]; j++) {
4656 char type = types[j];
4658 switch (type) {
4659 case TS_OFFSET: /* label(destination position) */
4661 char buff[0x100];
4662 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
4663 snprintf(buff, sizeof(buff), "<L%03d>", lobj->label_no);
4664 rb_str_concat(str, rb_str_new2(buff));
4665 break;
4667 break;
4668 case TS_ISEQ: /* iseq */
4670 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
4671 VALUE val = Qnil;
4672 if (iseq) {
4673 val = iseq->self;
4675 rb_str_concat(str, rb_inspect(val));
4677 break;
4678 case TS_LINDEX:
4679 case TS_DINDEX:
4680 case TS_NUM: /* ulong */
4681 case TS_VALUE: /* VALUE */
4682 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4683 break;
4684 case TS_ID: /* ID */
4685 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4686 break;
4687 case TS_GENTRY:
4689 struct global_entry *entry = (struct global_entry *)
4690 (OPERAND_AT(iobj, j) & (~1));
4691 rb_str_cat2(str, rb_id2name(entry->id));
4693 case TS_IC: /* method cache */
4694 rb_str_cat2(str, "<ic>");
4695 break;
4696 case TS_CDHASH: /* case/when condition cache */
4697 rb_str_cat2(str, "<ch>");
4698 break;
4699 default:{
4700 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
4703 if (types[j + 1]) {
4704 rb_str_cat2(str, ", ");
4708 return str;
4711 static void
4712 dump_disasm_list(struct iseq_link_element *link)
4714 int pos = 0;
4715 INSN *iobj;
4716 LABEL *lobj;
4717 VALUE str;
4719 printf("-- raw disasm--------\n");
4721 while (link) {
4722 switch (link->type) {
4723 case ISEQ_ELEMENT_INSN:
4725 iobj = (INSN *)link;
4726 str = insn_data_to_s_detail(iobj);
4727 printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str),
4728 insn_data_line_no(iobj));
4729 pos += insn_data_length(iobj);
4730 break;
4732 case ISEQ_ELEMENT_LABEL:
4734 lobj = (LABEL *)link;
4735 printf("<L%03d>\n", lobj->label_no);
4736 break;
4738 case ISEQ_ELEMENT_NONE:
4740 printf("[none]\n");
4741 break;
4743 case ISEQ_ELEMENT_ADJUST:
4745 ADJUST *adjust = (ADJUST *)link;
4746 printf("adjust: [label: %d]\n", adjust->label->label_no);
4747 break;
4749 default:
4750 /* ignore */
4751 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
4753 link = link->next;
4755 printf("---------------------\n");
4758 VALUE
4759 insns_name_array(void)
4761 VALUE ary = rb_ary_new();
4762 int i;
4763 for (i = 0; i < sizeof(insn_name_info) / sizeof(insn_name_info[0]); i++) {
4764 rb_ary_push(ary, rb_str_new2(insn_name_info[i]));
4766 return ary;
4769 static LABEL *
4770 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
4772 LABEL *label = 0;
4773 st_data_t tmp;
4774 obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
4776 if (st_lookup(labels_table, obj, &tmp) == 0) {
4777 label = NEW_LABEL(0);
4778 st_insert(labels_table, obj, (st_data_t)label);
4780 else {
4781 label = (LABEL *)tmp;
4783 return label;
4786 static VALUE
4787 get_exception_sym2type(VALUE sym)
4789 static VALUE symRescue, symEnsure, symRetry;
4790 static VALUE symBreak, symRedo, symNext;
4792 if (symRescue == 0) {
4793 symRescue = ID2SYM(rb_intern("rescue"));
4794 symEnsure = ID2SYM(rb_intern("ensure"));
4795 symRetry = ID2SYM(rb_intern("retry"));
4796 symBreak = ID2SYM(rb_intern("break"));
4797 symRedo = ID2SYM(rb_intern("redo"));
4798 symNext = ID2SYM(rb_intern("next"));
4801 if (sym == symRescue) return CATCH_TYPE_RESCUE;
4802 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
4803 if (sym == symRetry) return CATCH_TYPE_RETRY;
4804 if (sym == symBreak) return CATCH_TYPE_BREAK;
4805 if (sym == symRedo) return CATCH_TYPE_REDO;
4806 if (sym == symNext) return CATCH_TYPE_NEXT;
4807 rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
4808 RSTRING_PTR(rb_inspect(sym)));
4809 return 0;
4812 static int
4813 iseq_build_exception(rb_iseq_t *iseq, struct st_table *labels_table,
4814 VALUE exception)
4816 int i;
4818 for (i=0; i<RARRAY_LEN(exception); i++) {
4819 VALUE v, type, *ptr, eiseqval;
4820 LABEL *lstart, *lend, *lcont;
4821 int sp;
4823 RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
4824 "Array", "to_ary");
4825 if (RARRAY_LEN(v) != 6) {
4826 rb_raise(rb_eSyntaxError, "wrong exception entry");
4828 ptr = RARRAY_PTR(v);
4829 type = get_exception_sym2type(ptr[0]);
4830 if (ptr[1] == Qnil) {
4831 eiseqval = 0;
4833 else {
4834 eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil);
4837 lstart = register_label(iseq, labels_table, ptr[2]);
4838 lend = register_label(iseq, labels_table, ptr[3]);
4839 lcont = register_label(iseq, labels_table, ptr[4]);
4840 sp = NUM2INT(ptr[5]);
4842 ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
4844 return COMPILE_OK;
4847 struct st_table *insn_make_insn_table(void);
4849 static int
4850 iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
4851 VALUE body, struct st_table *labels_table)
4853 /* TODO: body should be freezed */
4854 VALUE *ptr = RARRAY_PTR(body);
4855 int len = RARRAY_LEN(body);
4856 int i, j;
4857 int line_no = 0;
4859 * index -> LABEL *label
4861 static struct st_table *insn_table;
4863 if (insn_table == 0) {
4864 insn_table = insn_make_insn_table();
4867 for (i=0; i<len; i++) {
4868 VALUE obj = ptr[i];
4870 if (SYMBOL_P(obj)) {
4871 LABEL *label = register_label(iseq, labels_table, obj);
4872 ADD_LABEL(anchor, label);
4874 else if (FIXNUM_P(obj)) {
4875 line_no = NUM2INT(obj);
4877 else if (TYPE(obj) == T_ARRAY) {
4878 VALUE *argv = 0;
4879 int argc = RARRAY_LEN(obj) - 1;
4880 VALUE insn_id;
4881 VALUE insn;
4883 insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
4884 if (st_lookup(insn_table, insn, &insn_id) == 0) {
4885 /* TODO: exception */
4886 RB_GC_GUARD(insn) = rb_inspect(insn);
4887 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4888 "unknown instruction: %s", RSTRING_PTR(insn));
4891 if (argc != insn_len(insn_id)-1) {
4892 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4893 "operand size mismatch");
4896 if (argc > 0) {
4897 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
4898 for (j=0; j<argc; j++) {
4899 VALUE op = rb_ary_entry(obj, j+1);
4900 switch (insn_op_type(insn_id, j)) {
4901 case TS_OFFSET: {
4902 LABEL *label = register_label(iseq, labels_table, op);
4903 argv[j] = (VALUE)label;
4904 break;
4906 case TS_LINDEX:
4907 case TS_DINDEX:
4908 case TS_NUM:
4909 argv[j] = (NUM2INT(op), op);
4910 break;
4911 case TS_VALUE:
4912 argv[j] = op;
4913 iseq_add_mark_object(iseq, op);
4914 break;
4915 case TS_ISEQ:
4917 if (op != Qnil) {
4918 if (TYPE(op) == T_ARRAY) {
4919 argv[j] = iseq_load(0, op, iseq->self, Qnil);
4921 else if (CLASS_OF(op) == rb_cISeq) {
4922 argv[j] = op;
4924 else {
4925 rb_raise(rb_eSyntaxError, "ISEQ is required");
4927 iseq_add_mark_object(iseq, argv[j]);
4929 else {
4930 argv[j] = 0;
4933 break;
4934 case TS_GENTRY:
4935 op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
4936 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
4937 break;
4938 case TS_IC:
4939 argv[j] = (VALUE)NEW_INLINE_CACHE_ENTRY();
4940 iseq_add_mark_object(iseq, argv[j]);
4941 break;
4942 case TS_ID:
4943 argv[j] = rb_convert_type(op, T_SYMBOL,
4944 "Symbol", "to_sym");
4945 break;
4946 case TS_CDHASH:
4948 int i;
4949 op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
4950 for (i=0; i<RARRAY_LEN(op); i+=2) {
4951 VALUE sym = rb_ary_entry(op, i+1);
4952 LABEL *label =
4953 register_label(iseq, labels_table, sym);
4954 rb_ary_store(op, i+1, (VALUE)label | 1);
4956 argv[j] = op;
4958 break;
4959 default:
4960 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type(insn_id, j));
4964 ADD_ELEM(anchor,
4965 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
4966 insn_id, argc, argv));
4968 else {
4969 rb_raise(rb_eTypeError, "unexpected object for instruction");
4972 st_free_table(labels_table);
4973 iseq_setup(iseq, anchor);
4974 return COMPILE_OK;
4977 #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
4978 #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
4979 #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
4980 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
4982 VALUE
4983 iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
4984 VALUE exception, VALUE body)
4986 int i;
4987 int opt = 0;
4988 ID *tbl;
4989 struct st_table *labels_table = st_init_numtable();
4991 DECL_ANCHOR(anchor);
4993 INIT_ANCHOR(anchor);
4994 if (iseq->type == ISEQ_TYPE_METHOD ||
4995 iseq->type == ISEQ_TYPE_TOP ||
4996 iseq->type == ISEQ_TYPE_CLASS) {
4997 opt = 1;
5000 iseq->local_table_size = opt + RARRAY_LEN(locals);
5001 iseq->local_table = tbl = (ID *)ALLOC_N(ID *, iseq->local_table_size);
5002 iseq->local_size = opt + iseq->local_table_size;
5004 for (i=0; i<RARRAY_LEN(locals); i++) {
5005 VALUE lv = RARRAY_PTR(locals)[i];
5006 tbl[i] = FIXNUM_P(lv) ? FIX2INT(lv) : SYM2ID(CHECK_SYMBOL(lv));
5009 /* args */
5010 if (FIXNUM_P(args)) {
5011 iseq->arg_size = iseq->argc = FIX2INT(args);
5012 iseq->arg_simple = 1;
5014 else {
5015 int i = 0;
5016 VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
5017 VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
5018 VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
5019 VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
5020 VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
5021 VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
5022 VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
5024 iseq->argc = FIX2INT(argc);
5025 iseq->arg_rest = FIX2INT(arg_rest);
5026 iseq->arg_post_len = FIX2INT(arg_post_len);
5027 iseq->arg_post_start = FIX2INT(arg_post_start);
5028 iseq->arg_block = FIX2INT(arg_block);
5029 iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, RARRAY_LEN(arg_opt_labels));
5031 if (iseq->arg_block != -1) {
5032 iseq->arg_size = iseq->arg_block + 1;
5034 else if (iseq->arg_post_len) {
5035 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
5037 else if (iseq->arg_rest != -1) {
5038 iseq->arg_size = iseq->arg_rest + 1;
5040 else {
5041 iseq->arg_size = iseq->argc + iseq->arg_opts;
5044 for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
5045 iseq->arg_opt_table[i] =
5046 (VALUE)register_label(iseq, labels_table,
5047 rb_ary_entry(arg_opt_labels, i));
5050 iseq->arg_simple = NUM2INT(arg_simple);
5053 /* exception */
5054 iseq_build_exception(iseq, labels_table, exception);
5056 /* body */
5057 iseq_build_body(iseq, anchor, body, labels_table);
5058 return iseq->self;