add a test for IA64 Debian GNU/Linux Etch.
[ruby-svn.git] / compile.c
bloba5604fa9ae5490f9aeb414e4e762e8444653a83a
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 (nd_type(cpath) == NODE_COLON3) {
2287 /* toplevel class ::Foo */
2288 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
2290 else if (cpath->nd_head) {
2291 /* Bar::Foo */
2292 COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
2294 else {
2295 /* class at cbase Foo */
2296 ADD_INSN1(ret, nd_line(cpath), putobject, Qundef);
2298 return COMPILE_OK;
2301 static int
2302 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2303 NODE *node, LABEL **lfinish, VALUE needstr)
2305 char *estr = 0;
2306 enum node_type type;
2308 switch (type = nd_type(node)) {
2310 /* easy literals */
2311 case NODE_NIL:
2312 estr = "nil";
2313 break;
2314 case NODE_SELF:
2315 estr = "self";
2316 break;
2317 case NODE_TRUE:
2318 estr = "true";
2319 break;
2320 case NODE_FALSE:
2321 estr = "false";
2322 break;
2324 case NODE_ARRAY:{
2325 NODE *vals = node;
2327 do {
2328 defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
2330 if (lfinish[1]) {
2331 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2333 else {
2334 LABEL *lcont = NEW_LABEL(nd_line(node));
2335 lfinish[1] = NEW_LABEL(nd_line(node));
2336 ADD_INSNL(ret, nd_line(node), branchif, lcont);
2337 ADD_LABEL(ret, lfinish[1]);
2338 ADD_INSN(ret, nd_line(node), putnil);
2339 ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
2340 ADD_LABEL(ret, lcont);
2342 } while ((vals = vals->nd_next) != NULL);
2344 case NODE_STR:
2345 case NODE_LIT:
2346 case NODE_ZARRAY:
2347 estr = "expression";
2348 break;
2350 /* variables */
2351 case NODE_LVAR:
2352 case NODE_DVAR:
2353 estr = "local-variable";
2354 break;
2356 case NODE_IVAR:
2357 ADD_INSN(ret, nd_line(node), putnil);
2358 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR),
2359 ID2SYM(node->nd_vid), needstr);
2360 return 1;
2362 case NODE_GVAR:
2363 ADD_INSN(ret, nd_line(node), putnil);
2364 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR),
2365 ((VALUE)node->nd_entry) | 1, needstr);
2366 return 1;
2368 case NODE_CVAR:
2369 ADD_INSN(ret, nd_line(node), putnil);
2370 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR),
2371 ID2SYM(node->nd_vid), needstr);
2372 return 1;
2374 case NODE_CONST:
2375 ADD_INSN(ret, nd_line(node), putnil);
2376 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2377 ID2SYM(node->nd_vid), needstr);
2378 return 1;
2379 case NODE_COLON2:
2380 if (!lfinish[1]) {
2381 lfinish[1] = NEW_LABEL(nd_line(node));
2383 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
2384 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2386 if (rb_is_const_id(node->nd_mid)) {
2387 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2388 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2389 ID2SYM(node->nd_mid), needstr);
2391 else {
2392 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2393 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2394 ID2SYM(node->nd_mid), needstr);
2396 return 1;
2397 case NODE_COLON3:
2398 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
2399 ADD_INSN3(ret, nd_line(node), defined,
2400 INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
2401 return 1;
2403 /* method dispatch */
2404 case NODE_CALL:
2405 case NODE_VCALL:
2406 case NODE_FCALL:
2407 case NODE_ATTRASGN:{
2408 int self = Qtrue;
2410 switch (type) {
2411 case NODE_ATTRASGN:
2412 if (node->nd_recv == (NODE *)1) break;
2413 case NODE_CALL:
2414 self = Qfalse;
2415 break;
2416 default:
2417 /* through */;
2419 if (!lfinish[1]) {
2420 lfinish[1] = NEW_LABEL(nd_line(node));
2422 if (node->nd_args) {
2423 defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
2424 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2426 if (!self) {
2427 LABEL *lstart = NEW_LABEL(nd_line(node));
2428 LABEL *lend = NEW_LABEL(nd_line(node));
2429 VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
2430 rb_str_concat(rb_str_new2
2431 ("defined guard in "),
2432 iseq->name),
2433 ISEQ_TYPE_DEFINED_GUARD);
2435 defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
2436 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2438 ADD_LABEL(ret, lstart);
2439 COMPILE(ret, "defined/recv", node->nd_recv);
2440 ADD_LABEL(ret, lend);
2441 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
2442 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2443 ID2SYM(node->nd_mid), needstr);
2445 else {
2446 ADD_INSN(ret, nd_line(node), putself);
2447 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
2448 ID2SYM(node->nd_mid), needstr);
2450 return 1;
2453 case NODE_YIELD:
2454 ADD_INSN(ret, nd_line(node), putnil);
2455 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0,
2456 needstr);
2457 return 1;
2459 case NODE_BACK_REF:
2460 case NODE_NTH_REF:
2461 ADD_INSN(ret, nd_line(node), putnil);
2462 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
2463 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
2464 needstr);
2465 return 1;
2467 case NODE_ZSUPER:
2468 ADD_INSN(ret, nd_line(node), putnil);
2469 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
2470 needstr);
2471 return 1;
2473 case NODE_OP_ASGN1:
2474 case NODE_OP_ASGN2:
2475 case NODE_MASGN:
2476 case NODE_LASGN:
2477 case NODE_DASGN:
2478 case NODE_DASGN_CURR:
2479 case NODE_GASGN:
2480 case NODE_IASGN:
2481 case NODE_CDECL:
2482 case NODE_CVDECL:
2483 case NODE_CVASGN:
2484 estr = "assignment";
2485 break;
2487 default:{
2488 LABEL *lstart = NEW_LABEL(nd_line(node));
2489 LABEL *lend = NEW_LABEL(nd_line(node));
2490 VALUE ensure = NEW_CHILD_ISEQVAL(NEW_NIL(),
2491 rb_str_concat(rb_str_new2
2492 ("defined guard in "),
2493 iseq->name),
2494 ISEQ_TYPE_DEFINED_GUARD);
2496 ADD_LABEL(ret, lstart);
2497 COMPILE(ret, "defined expr (others)", node);
2498 if (!lfinish[1]) {
2499 lfinish[1] = NEW_LABEL(nd_line(node));
2501 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2502 if (needstr) {
2503 ADD_INSN1(ret, nd_line(node), putstring, rb_str_new2("expression"));
2505 else {
2506 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2508 ADD_LABEL(ret, lend);
2510 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, lstart, lend, ensure, lfinish[1]);
2511 return 1;
2512 } /* end of default */
2515 if (estr != 0) {
2516 if (needstr != Qfalse) {
2517 VALUE str = rb_str_new2(estr);
2518 ADD_INSN1(ret, nd_line(node), putstring, str);
2519 iseq_add_mark_object_compile_time(iseq, str);
2521 else {
2522 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2524 return 1;
2526 return 0;
2529 #define BUFSIZE 0x100
2531 static VALUE
2532 make_name_for_block(rb_iseq_t *iseq)
2534 if (iseq->parent_iseq == 0) {
2535 return rb_sprintf("block in %s", RSTRING_PTR(iseq->name));
2537 else {
2538 int level = 1;
2539 rb_iseq_t *ip = iseq;
2540 while (ip->local_iseq != ip) {
2541 ip = ip->parent_iseq;
2542 level++;
2544 return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->name));
2548 static void
2549 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
2550 LABEL *lstart, LABEL *lend)
2552 struct ensure_range *ne =
2553 compile_data_alloc(iseq, sizeof(struct ensure_range));
2555 while (erange->next != 0) {
2556 erange = erange->next;
2558 ne->next = 0;
2559 ne->begin = lend;
2560 ne->end = erange->end;
2561 erange->end = lstart;
2563 erange->next = ne;
2566 static void
2567 add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq)
2569 struct iseq_compile_data_ensure_node_stack *enlp =
2570 iseq->compile_data->ensure_node_stack;
2571 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
2572 DECL_ANCHOR(ensure);
2574 INIT_ANCHOR(ensure);
2575 while (enlp) {
2576 DECL_ANCHOR(ensure_part);
2577 LABEL *lstart = NEW_LABEL(0);
2578 LABEL *lend = NEW_LABEL(0);
2580 INIT_ANCHOR(ensure_part);
2581 add_ensure_range(iseq, enlp->erange, lstart, lend);
2583 iseq->compile_data->ensure_node_stack = enlp->prev;
2584 ADD_LABEL(ensure_part, lstart);
2585 COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
2586 ADD_LABEL(ensure_part, lend);
2588 ADD_SEQ(ensure, ensure_part);
2589 enlp = enlp->prev;
2591 iseq->compile_data->ensure_node_stack = prev_enlp;
2592 ADD_SEQ(ret, ensure);
2595 static VALUE
2596 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned long *flag)
2598 VALUE argc = INT2FIX(0);
2599 int nsplat = 0;
2600 DECL_ANCHOR(arg_block);
2601 DECL_ANCHOR(args_splat);
2603 INIT_ANCHOR(arg_block);
2604 INIT_ANCHOR(args_splat);
2605 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
2606 COMPILE(arg_block, "block", argn->nd_body);
2607 *flag |= VM_CALL_ARGS_BLOCKARG_BIT;
2608 argn = argn->nd_head;
2611 setup_argn:
2612 if (argn) {
2613 switch (nd_type(argn)) {
2614 case NODE_SPLAT: {
2615 COMPILE(args, "args (splat)", argn->nd_head);
2616 argc = INT2FIX(1);
2617 nsplat++;
2618 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2619 break;
2621 case NODE_ARGSCAT:
2622 case NODE_ARGSPUSH: {
2623 int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
2624 DECL_ANCHOR(tmp);
2626 INIT_ANCHOR(tmp);
2627 COMPILE(tmp, "args (cat: splat)", argn->nd_body);
2628 if (next_is_array && nsplat == 0) {
2629 /* none */
2631 else {
2632 if (nd_type(argn) == NODE_ARGSCAT) {
2633 ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
2635 else {
2636 ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1));
2639 INSERT_LIST(args_splat, tmp);
2640 nsplat++;
2641 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2643 if (next_is_array) {
2644 argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) + 1);
2645 POP_ELEMENT(args);
2647 else {
2648 argn = argn->nd_head;
2649 goto setup_argn;
2651 break;
2653 case NODE_ARRAY: {
2654 argc = INT2FIX(compile_array(iseq, args, argn, Qfalse));
2655 POP_ELEMENT(args);
2656 break;
2658 default: {
2659 rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn)));
2664 if (nsplat > 1) {
2665 int i;
2666 for (i=1; i<nsplat; i++) {
2667 ADD_INSN(args_splat, nd_line(args), concatarray);
2671 if (!LIST_SIZE_ZERO(args_splat)) {
2672 ADD_SEQ(args, args_splat);
2675 if (*flag & VM_CALL_ARGS_BLOCKARG_BIT) {
2676 ADD_SEQ(args, arg_block);
2678 return argc;
2683 compile each node
2685 self: InstructionSequence
2686 node: Ruby compiled node
2687 poped: This node will be poped
2689 static int
2690 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
2692 enum node_type type;
2694 if (node == 0) {
2695 if (!poped) {
2696 debugs("node: NODE_NIL(implicit)\n");
2697 ADD_INSN(ret, iseq->compile_data->last_line, putnil);
2699 return COMPILE_OK;
2702 iseq->compile_data->last_line = nd_line(node);
2703 debug_node_start(node);
2705 type = nd_type(node);
2707 if (node->flags & NODE_FL_NEWLINE) {
2708 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_LINE);
2711 switch (type) {
2712 case NODE_BLOCK:{
2713 while (node && nd_type(node) == NODE_BLOCK) {
2714 COMPILE_(ret, "BLOCK body", node->nd_head,
2715 (node->nd_next == 0 && poped == 0) ? 0 : 1);
2716 node = node->nd_next;
2718 if (node) {
2719 COMPILE_(ret, "BLOCK next", node->nd_next, poped);
2721 break;
2723 case NODE_IF:{
2724 DECL_ANCHOR(cond_seq);
2725 DECL_ANCHOR(then_seq);
2726 DECL_ANCHOR(else_seq);
2727 LABEL *then_label, *else_label, *end_label;
2729 INIT_ANCHOR(cond_seq);
2730 INIT_ANCHOR(then_seq);
2731 INIT_ANCHOR(else_seq);
2732 then_label = NEW_LABEL(nd_line(node));
2733 else_label = NEW_LABEL(nd_line(node));
2734 end_label = NEW_LABEL(nd_line(node));
2736 compile_branch_condition(iseq, cond_seq, node->nd_cond,
2737 then_label, else_label);
2738 COMPILE_(then_seq, "then", node->nd_body, poped);
2739 COMPILE_(else_seq, "else", node->nd_else, poped);
2741 ADD_SEQ(ret, cond_seq);
2743 ADD_LABEL(ret, then_label);
2744 ADD_SEQ(ret, then_seq);
2745 ADD_INSNL(ret, nd_line(node), jump, end_label);
2747 ADD_LABEL(ret, else_label);
2748 ADD_SEQ(ret, else_seq);
2750 ADD_LABEL(ret, end_label);
2752 break;
2754 case NODE_CASE:{
2755 NODE *vals;
2756 NODE *tempnode = node;
2757 LABEL *endlabel, *elselabel;
2758 DECL_ANCHOR(head);
2759 DECL_ANCHOR(body_seq);
2760 DECL_ANCHOR(cond_seq);
2761 VALUE special_literals = rb_ary_new();
2763 INIT_ANCHOR(head);
2764 INIT_ANCHOR(body_seq);
2765 INIT_ANCHOR(cond_seq);
2766 if (node->nd_head == 0) {
2767 COMPILE_(ret, "when", node->nd_body, poped);
2768 break;
2770 COMPILE(head, "case base", node->nd_head);
2772 node = node->nd_body;
2773 type = nd_type(node);
2775 if (type != NODE_WHEN) {
2776 COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
2779 endlabel = NEW_LABEL(nd_line(node));
2780 elselabel = NEW_LABEL(nd_line(node));
2782 ADD_SEQ(ret, head); /* case VAL */
2784 while (type == NODE_WHEN) {
2785 LABEL *l1;
2787 l1 = NEW_LABEL(nd_line(node));
2788 ADD_LABEL(body_seq, l1);
2789 ADD_INSN(body_seq, nd_line(node), pop);
2790 COMPILE_(body_seq, "when body", node->nd_body, poped);
2791 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2793 vals = node->nd_head;
2794 if (vals) {
2795 switch (nd_type(vals)) {
2796 case NODE_ARRAY:
2797 special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals);
2798 break;
2799 case NODE_SPLAT:
2800 case NODE_ARGSCAT:
2801 case NODE_ARGSPUSH:
2802 special_literals = 0;
2803 COMPILE(cond_seq, "when/cond splat", vals);
2804 ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
2805 ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
2806 break;
2807 default:
2808 rb_bug("NODE_CASE: unknown node (%s)",
2809 ruby_node_name(nd_type(vals)));
2812 else {
2813 rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
2816 node = node->nd_next;
2817 if (!node) {
2818 break;
2820 type = nd_type(node);
2822 /* else */
2823 if (node) {
2824 ADD_LABEL(cond_seq, elselabel);
2825 ADD_INSN(cond_seq, nd_line(node), pop);
2826 COMPILE_(cond_seq, "else", node, poped);
2827 ADD_INSNL(cond_seq, nd_line(node), jump, endlabel);
2829 else {
2830 debugs("== else (implicit)\n");
2831 ADD_LABEL(cond_seq, elselabel);
2832 ADD_INSN(cond_seq, nd_line(tempnode), pop);
2833 if (!poped) {
2834 ADD_INSN(cond_seq, nd_line(tempnode), putnil);
2836 ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
2839 if (special_literals) {
2840 ADD_INSN(ret, nd_line(tempnode), dup);
2841 ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch,
2842 special_literals, elselabel);
2843 iseq_add_mark_object_compile_time(iseq, special_literals);
2846 ADD_SEQ(ret, cond_seq);
2847 ADD_SEQ(ret, body_seq);
2848 ADD_LABEL(ret, endlabel);
2849 break;
2851 case NODE_WHEN:{
2852 NODE *vals;
2853 NODE *val;
2854 NODE *orig_node = node;
2855 LABEL *endlabel;
2856 DECL_ANCHOR(body_seq);
2858 INIT_ANCHOR(body_seq);
2859 endlabel = NEW_LABEL(nd_line(node));
2861 while (node && nd_type(node) == NODE_WHEN) {
2862 LABEL *l1 = NEW_LABEL(nd_line(node));
2863 ADD_LABEL(body_seq, l1);
2864 COMPILE_(body_seq, "when", node->nd_body, poped);
2865 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2867 vals = node->nd_head;
2868 if (vals && nd_type(vals) == NODE_ARRAY) {
2869 while (vals) {
2870 val = vals->nd_head;
2871 COMPILE(ret, "when2", val);
2872 ADD_INSNL(ret, nd_line(val), branchif, l1);
2873 vals = vals->nd_next;
2876 else if (nd_type(vals) == NODE_SPLAT ||
2877 nd_type(vals) == NODE_ARGSCAT ||
2878 nd_type(vals) == NODE_ARGSPUSH) {
2880 NODE *val = vals->nd_head;
2882 if (nd_type(vals) == NODE_ARGSCAT || nd_type(vals) == NODE_ARGSPUSH) {
2883 NODE *vs = vals->nd_head;
2884 val = vals->nd_body;
2886 while (vs) {
2887 NODE* val = vs->nd_head;
2888 COMPILE(ret, "when/argscat", val);
2889 ADD_INSNL(ret, nd_line(val), branchif, l1);
2890 vs = vs->nd_next;
2894 ADD_INSN(ret, nd_line(val), putnil);
2895 COMPILE(ret, "when2/splat", val);
2896 ADD_INSN1(ret, nd_line(val), checkincludearray, Qfalse);
2897 ADD_INSN(ret, nd_line(val), pop);
2898 ADD_INSNL(ret, nd_line(val), branchif, l1);
2900 else {
2901 rb_bug("err");
2903 node = node->nd_next;
2905 /* else */
2906 COMPILE_(ret, "else", node, poped);
2907 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
2909 ADD_SEQ(ret, body_seq);
2910 ADD_LABEL(ret, endlabel);
2912 break;
2914 case NODE_OPT_N:
2915 case NODE_WHILE:
2916 case NODE_UNTIL:{
2917 LABEL *prev_start_label = iseq->compile_data->start_label;
2918 LABEL *prev_end_label = iseq->compile_data->end_label;
2919 LABEL *prev_redo_label = iseq->compile_data->redo_label;
2920 VALUE prev_loopval_popped = iseq->compile_data->loopval_popped;
2922 struct iseq_compile_data_ensure_node_stack *enlp =
2923 iseq->compile_data->ensure_node_stack;
2925 LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(nd_line(node)); /* next */
2926 LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(nd_line(node)); /* redo */
2927 LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(nd_line(node)); /* break */
2928 LABEL *end_label = NEW_LABEL(nd_line(node));
2930 iseq->compile_data->loopval_popped = 0;
2931 iseq->compile_data->ensure_node_stack = 0;
2933 if (type == NODE_OPT_N || node->nd_state == 1) {
2934 ADD_INSNL(ret, nd_line(node), jump, next_label);
2937 ADD_LABEL(ret, redo_label);
2938 COMPILE_POPED(ret, "while body", node->nd_body);
2939 ADD_LABEL(ret, next_label); /* next */
2941 if (type == NODE_WHILE) {
2942 compile_branch_condition(iseq, ret, node->nd_cond,
2943 redo_label, end_label);
2945 else if (type == NODE_UNTIL) {
2946 /* untile */
2947 compile_branch_condition(iseq, ret, node->nd_cond,
2948 end_label, redo_label);
2950 else {
2951 ADD_CALL_RECEIVER(ret, nd_line(node));
2952 ADD_CALL(ret, nd_line(node), ID2SYM(idGets), INT2FIX(0));
2953 ADD_INSNL(ret, nd_line(node), branchif, redo_label);
2954 /* opt_n */
2957 ADD_LABEL(ret, end_label);
2959 if (node->nd_state == Qundef) {
2960 /* ADD_INSN(ret, nd_line(node), putundef); */
2961 rb_bug("unsupported: putundef");
2963 else {
2964 ADD_INSN(ret, nd_line(node), putnil);
2967 ADD_LABEL(ret, break_label); /* braek */
2969 if (poped) {
2970 ADD_INSN(ret, nd_line(node), pop);
2973 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
2974 0, break_label);
2975 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT | 0x10000, redo_label,
2976 break_label, 0, iseq->compile_data->start_label);
2977 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
2978 iseq->compile_data->redo_label);
2980 iseq->compile_data->start_label = prev_start_label;
2981 iseq->compile_data->end_label = prev_end_label;
2982 iseq->compile_data->redo_label = prev_redo_label;
2983 iseq->compile_data->loopval_popped = prev_loopval_popped;
2984 iseq->compile_data->ensure_node_stack = enlp;
2985 break;
2987 case NODE_ITER:
2988 case NODE_FOR:{
2989 VALUE prevblock = iseq->compile_data->current_block;
2990 LABEL *retry_label = NEW_LABEL(nd_line(node));
2991 LABEL *retry_end_l = NEW_LABEL(nd_line(node));
2992 ID mid = 0;
2994 ADD_LABEL(ret, retry_label);
2995 if (nd_type(node) == NODE_FOR) {
2996 COMPILE(ret, "iter caller (for)", node->nd_iter);
2998 iseq->compile_data->current_block =
2999 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3000 ISEQ_TYPE_BLOCK);
3002 mid = idEach;
3003 ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
3004 iseq->compile_data->current_block, INT2FIX(0));
3006 else {
3007 iseq->compile_data->current_block =
3008 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3009 ISEQ_TYPE_BLOCK);
3010 COMPILE(ret, "iter caller", node->nd_iter);
3012 ADD_LABEL(ret, retry_end_l);
3014 if (poped) {
3015 ADD_INSN(ret, nd_line(node), pop);
3018 iseq->compile_data->current_block = prevblock;
3020 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
3022 break;
3024 case NODE_BREAK:{
3025 unsigned long level = 0;
3027 if (iseq->compile_data->redo_label != 0) {
3028 /* while/until */
3029 LABEL *splabel = NEW_LABEL(0);
3030 ADD_LABEL(ret, splabel);
3031 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3032 COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
3033 add_ensure_iseq(ret, iseq);
3034 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3035 ADD_ADJUST_RESTORE(ret, splabel);
3037 if (!poped) {
3038 ADD_INSN(ret, nd_line(node), putnil);
3041 else if (iseq->type == ISEQ_TYPE_BLOCK) {
3042 break_by_insn:
3043 /* escape from block */
3044 COMPILE(ret, "break val (block)", node->nd_stts);
3045 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x02) /* TAG_BREAK */ );
3046 if (poped) {
3047 ADD_INSN(ret, nd_line(node), pop);
3050 else if (iseq->type == ISEQ_TYPE_EVAL) {
3051 break_in_eval:
3052 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
3054 else {
3055 rb_iseq_t *ip = iseq->parent_iseq;
3056 while (ip) {
3057 level++;
3058 if (ip->compile_data->redo_label != 0) {
3059 level = 0x8000;
3060 if (ip->compile_data->loopval_popped == 0) {
3061 /* need value */
3062 level |= 0x4000;
3064 goto break_by_insn;
3066 else if (ip->type == ISEQ_TYPE_BLOCK) {
3067 level <<= 16;
3068 goto break_by_insn;
3070 else if (ip->type == ISEQ_TYPE_EVAL) {
3071 goto break_in_eval;
3073 ip = ip->parent_iseq;
3075 COMPILE_ERROR((ERROR_ARGS "Invalid break"));
3077 break;
3079 case NODE_NEXT:{
3080 unsigned long level = 0;
3082 if (iseq->compile_data->redo_label != 0) {
3083 LABEL *splabel = NEW_LABEL(0);
3084 debugs("next in while loop\n");
3085 ADD_LABEL(ret, splabel);
3086 COMPILE(ret, "next val/valid syntax?", node->nd_stts);
3087 add_ensure_iseq(ret, iseq);
3088 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3089 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3090 ADD_ADJUST_RESTORE(ret, splabel);
3092 else if (iseq->compile_data->end_label) {
3093 LABEL *splabel = NEW_LABEL(0);
3094 debugs("next in block\n");
3095 ADD_LABEL(ret, splabel);
3096 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3097 COMPILE(ret, "next val", node->nd_stts);
3098 add_ensure_iseq(ret, iseq);
3099 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3100 ADD_ADJUST_RESTORE(ret, splabel);
3102 if (!poped) {
3103 ADD_INSN(ret, nd_line(node), putnil);
3106 else if (iseq->type == ISEQ_TYPE_EVAL) {
3107 next_in_eval:
3108 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
3110 else {
3111 rb_iseq_t *ip;
3112 ip = iseq;
3113 while (ip) {
3114 level = 0x8000;
3115 if (ip->compile_data->redo_label != 0) {
3116 /* while loop */
3117 break;
3119 else if (ip->type == ISEQ_TYPE_BLOCK) {
3120 level |= 0x4000;
3121 break;
3123 else if (ip->type == ISEQ_TYPE_EVAL) {
3124 goto next_in_eval;
3126 ip = ip->parent_iseq;
3128 if (ip != 0) {
3129 COMPILE(ret, "next val", node->nd_stts);
3130 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x03) /* TAG_NEXT */ );
3132 if (poped) {
3133 ADD_INSN(ret, nd_line(node), pop);
3136 else {
3137 COMPILE_ERROR((ERROR_ARGS "Invalid next"));
3140 break;
3142 case NODE_REDO:{
3143 if (iseq->compile_data->redo_label) {
3144 LABEL *splabel = NEW_LABEL(0);
3145 debugs("redo in while");
3146 ADD_LABEL(ret, splabel);
3147 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3148 add_ensure_iseq(ret, iseq);
3149 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->redo_label);
3150 ADD_ADJUST_RESTORE(ret, splabel);
3152 else if (iseq->type == ISEQ_TYPE_EVAL) {
3153 redo_in_eval:
3154 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
3156 else if (iseq->compile_data->start_label) {
3157 LABEL *splabel = NEW_LABEL(0);
3159 debugs("redo in block");
3160 ADD_LABEL(ret, splabel);
3161 add_ensure_iseq(ret, iseq);
3162 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3163 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3164 ADD_ADJUST_RESTORE(ret, splabel);
3166 if (!poped) {
3167 ADD_INSN(ret, nd_line(node), putnil);
3170 else {
3171 rb_iseq_t *ip;
3172 unsigned long level;
3173 level = 0x8000 | 0x4000;
3174 ip = iseq;
3175 while (ip) {
3176 if (ip->compile_data->redo_label != 0) {
3177 break;
3179 else if (ip->type == ISEQ_TYPE_BLOCK) {
3180 break;
3182 else if (ip->type == ISEQ_TYPE_EVAL) {
3183 goto redo_in_eval;
3185 ip = ip->parent_iseq;
3187 if (ip != 0) {
3188 ADD_INSN(ret, nd_line(node), putnil);
3189 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x05) /* TAG_REDO */ );
3191 if (poped) {
3192 ADD_INSN(ret, nd_line(node), pop);
3195 else {
3196 COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
3199 break;
3201 case NODE_RETRY:{
3202 if (iseq->type == ISEQ_TYPE_RESCUE) {
3203 ADD_INSN(ret, nd_line(node), putnil);
3204 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x04) /* TAG_RETRY */ );
3206 if (poped) {
3207 ADD_INSN(ret, nd_line(node), pop);
3210 else {
3211 COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
3213 break;
3215 case NODE_BEGIN:{
3216 COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
3217 break;
3219 case NODE_RESCUE:{
3220 LABEL *lstart = NEW_LABEL(nd_line(node));
3221 LABEL *lend = NEW_LABEL(nd_line(node));
3222 LABEL *lcont = NEW_LABEL(nd_line(node));
3223 VALUE rescue = NEW_CHILD_ISEQVAL(
3224 node->nd_resq,
3225 rb_str_concat(rb_str_new2("rescue in "), iseq->name),
3226 ISEQ_TYPE_RESCUE);
3228 ADD_LABEL(ret, lstart);
3229 COMPILE(ret, "rescue head", node->nd_head);
3230 ADD_LABEL(ret, lend);
3231 if (node->nd_else) {
3232 ADD_INSN(ret, nd_line(node), pop);
3233 COMPILE(ret, "rescue else", node->nd_else);
3235 ADD_INSN(ret, nd_line(node), nop);
3236 ADD_LABEL(ret, lcont);
3238 if (poped) {
3239 ADD_INSN(ret, nd_line(node), pop);
3242 /* resgister catch entry */
3243 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
3244 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
3245 break;
3247 case NODE_RESBODY:{
3248 NODE *resq = node;
3249 NODE *narg;
3250 LABEL *label_miss, *label_hit;
3252 while (resq) {
3253 label_miss = NEW_LABEL(nd_line(node));
3254 label_hit = NEW_LABEL(nd_line(node));
3256 narg = resq->nd_args;
3257 if (narg) {
3258 switch (nd_type(narg)) {
3259 case NODE_ARRAY:
3260 while (narg) {
3261 COMPILE(ret, "rescue arg", narg->nd_head);
3262 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3263 INT2FIX(0));
3264 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3265 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3266 narg = narg->nd_next;
3268 break;
3269 case NODE_SPLAT:
3270 case NODE_ARGSCAT:
3271 case NODE_ARGSPUSH:
3272 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3273 INT2FIX(0));
3274 COMPILE(ret, "rescue/cond splat", narg);
3275 ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
3276 ADD_INSN(ret, nd_line(node), swap);
3277 ADD_INSN(ret, nd_line(node), pop);
3278 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3279 break;
3280 default:
3281 rb_bug("NODE_RESBODY: unknown node (%s)",
3282 ruby_node_name(nd_type(narg)));
3285 else {
3286 ADD_INSN1(ret, nd_line(node), putobject,
3287 rb_eStandardError);
3288 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
3289 INT2FIX(0));
3290 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3291 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3293 ADD_INSNL(ret, nd_line(node), jump, label_miss);
3294 ADD_LABEL(ret, label_hit);
3295 COMPILE(ret, "resbody body", resq->nd_body);
3296 if (iseq->compile_data->option->tailcall_optimization) {
3297 ADD_INSN(ret, nd_line(node), nop);
3299 ADD_INSN(ret, nd_line(node), leave);
3300 ADD_LABEL(ret, label_miss);
3301 resq = resq->nd_head;
3303 break;
3305 case NODE_ENSURE:{
3306 DECL_ANCHOR(ensr);
3307 VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
3308 rb_str_concat(rb_str_new2
3309 ("ensure in "),
3310 iseq->name),
3311 ISEQ_TYPE_ENSURE);
3312 LABEL *lstart = NEW_LABEL(nd_line(node));
3313 LABEL *lend = NEW_LABEL(nd_line(node));
3314 LABEL *lcont = NEW_LABEL(nd_line(node));
3315 struct ensure_range er = { 0 };
3316 struct iseq_compile_data_ensure_node_stack enl;
3317 struct ensure_range *erange;
3319 INIT_ANCHOR(ensr);
3320 er.begin = lstart;
3321 er.end = lend;
3322 enl.ensure_node = node->nd_ensr;
3323 enl.prev = iseq->compile_data->ensure_node_stack; /* prev */
3324 enl.erange = &er;
3325 COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
3327 iseq->compile_data->ensure_node_stack = &enl;
3329 ADD_LABEL(ret, lstart);
3330 COMPILE_(ret, "ensure head", node->nd_head, poped);
3331 ADD_LABEL(ret, lend);
3332 if (ensr->anchor.next == 0) {
3333 ADD_INSN(ret, nd_line(node), nop);
3335 else {
3336 ADD_SEQ(ret, ensr);
3338 ADD_LABEL(ret, lcont);
3340 erange = iseq->compile_data->ensure_node_stack->erange;
3341 while (erange) {
3342 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
3343 ensure, lcont);
3344 erange = erange->next;
3346 iseq->compile_data->ensure_node_stack = enl.prev;
3347 break;
3350 case NODE_AND:
3351 case NODE_OR:{
3352 LABEL *end_label = NEW_LABEL(nd_line(node));
3353 COMPILE(ret, "nd_1st", node->nd_1st);
3354 if (!poped) {
3355 ADD_INSN(ret, nd_line(node), dup);
3357 if (type == NODE_AND) {
3358 ADD_INSNL(ret, nd_line(node), branchunless, end_label);
3360 else {
3361 ADD_INSNL(ret, nd_line(node), branchif, end_label);
3363 if (!poped) {
3364 ADD_INSN(ret, nd_line(node), pop);
3366 COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
3367 ADD_LABEL(ret, end_label);
3368 break;
3371 case NODE_MASGN:{
3372 compile_massign(iseq, ret, node, poped);
3373 break;
3376 case NODE_LASGN:{
3377 ID id = node->nd_vid;
3378 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3380 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
3381 COMPILE(ret, "rvalue", node->nd_value);
3383 if (!poped) {
3384 ADD_INSN(ret, nd_line(node), dup);
3386 ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx));
3388 break;
3390 case NODE_DASGN:
3391 case NODE_DASGN_CURR:{
3392 int idx, lv, ls;
3393 COMPILE(ret, "dvalue", node->nd_value);
3394 debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
3396 if (!poped) {
3397 ADD_INSN(ret, nd_line(node), dup);
3400 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
3402 if (idx < 0) {
3403 rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
3406 ADD_INSN2(ret, nd_line(node), setdynamic,
3407 INT2FIX(ls - idx), INT2FIX(lv));
3408 break;
3410 case NODE_GASGN:{
3411 COMPILE(ret, "lvalue", node->nd_value);
3413 if (!poped) {
3414 ADD_INSN(ret, nd_line(node), dup);
3416 ADD_INSN1(ret, nd_line(node), setglobal,
3417 (((long)node->nd_entry) | 1));
3418 break;
3420 case NODE_IASGN:
3421 case NODE_IASGN2:{
3422 COMPILE(ret, "lvalue", node->nd_value);
3423 if (!poped) {
3424 ADD_INSN(ret, nd_line(node), dup);
3426 ADD_INSN1(ret, nd_line(node), setinstancevariable,
3427 ID2SYM(node->nd_vid));
3428 break;
3430 case NODE_CDECL:{
3431 COMPILE(ret, "lvalue", node->nd_value);
3433 if (!poped) {
3434 ADD_INSN(ret, nd_line(node), dup);
3437 if (node->nd_vid) {
3438 ADD_INSN1(ret, nd_line(node), putobject, Qundef);
3439 ADD_INSN1(ret, nd_line(node), setconstant,
3440 ID2SYM(node->nd_vid));
3442 else {
3443 compile_cpath(ret, iseq, node->nd_else);
3444 ADD_INSN1(ret, nd_line(node), setconstant,
3445 ID2SYM(node->nd_else->nd_mid));
3447 break;
3449 case NODE_CVASGN:{
3450 COMPILE(ret, "cvasgn val", node->nd_value);
3451 if (!poped) {
3452 ADD_INSN(ret, nd_line(node), dup);
3454 ADD_INSN1(ret, nd_line(node), setclassvariable,
3455 ID2SYM(node->nd_vid));
3456 break;
3458 case NODE_OP_ASGN1: {
3459 DECL_ANCHOR(args);
3460 VALUE argc;
3461 unsigned long flag = 0;
3462 ID id = node->nd_mid;
3465 * a[x] (op)= y
3467 * eval a # a
3468 * eval x # a x
3469 * dupn 2 # a x a x
3470 * send :[] # a x a[x]
3471 * eval y # a x a[x] y
3472 * send op # a x a[x]+y
3473 * send []= # ret
3477 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
3478 * NODE_OP_ASGN nd_recv
3479 * nd_args->nd_head
3480 * nd_args->nd_body
3481 * nd_mid
3484 COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
3485 if (nd_type(node->nd_args->nd_body) != NODE_ZARRAY) {
3486 INIT_ANCHOR(args);
3487 argc = setup_args(iseq, args, node->nd_args->nd_body, &flag);
3488 ADD_SEQ(ret, args);
3490 else {
3491 argc = INT2FIX(0);
3493 ADD_INSN1(ret, nd_line(node), dupn, INT2FIX(FIX2INT(argc)+1));
3494 ADD_SEND_R(ret, nd_line(node), ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
3496 if (id == 0 || id == 1) {
3497 /* 0: or, 1: and
3498 a[x] ||= y
3500 unless/if a[x]
3501 a[x]= y
3502 else
3506 LABEL *label = NEW_LABEL(nd_line(node));
3507 LABEL *lfin = NEW_LABEL(nd_line(node));
3509 if (id == 0) {
3510 /* or */
3511 ADD_INSN(ret, nd_line(node), dup);
3512 ADD_INSNL(ret, nd_line(node), branchif, label);
3513 ADD_INSN(ret, nd_line(node), pop);
3515 else {
3516 /* and */
3517 ADD_INSNL(ret, nd_line(node), branchunless, label);
3520 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3521 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3522 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3523 ADD_INSN(ret, nd_line(node), concatarray);
3524 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3525 argc, Qfalse, LONG2FIX(flag));
3527 else {
3528 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3529 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3531 ADD_INSNL(ret, nd_line(node), jump, lfin);
3532 ADD_LABEL(ret, label);
3533 if (id == 0) { /* or */
3534 ADD_INSN(ret, nd_line(node), swap);
3535 ADD_INSN(ret, nd_line(node), pop);
3536 ADD_INSN(ret, nd_line(node), swap);
3537 ADD_INSN(ret, nd_line(node), pop);
3539 else if (id == 1) { /* and */
3540 ADD_INSN(ret, nd_line(node), pop);
3541 ADD_INSN(ret, nd_line(node), pop);
3542 ADD_INSN(ret, nd_line(node), putnil);
3544 ADD_LABEL(ret, lfin);
3546 else {
3547 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3548 ADD_SEND(ret, nd_line(node), ID2SYM(id), INT2FIX(1));
3549 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3550 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3551 ADD_INSN(ret, nd_line(node), concatarray);
3552 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3553 argc, Qfalse, LONG2FIX(flag));
3555 else {
3556 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3557 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3561 if (poped) {
3562 ADD_INSN(ret, nd_line(node), pop);
3565 break;
3567 case NODE_OP_ASGN2:{
3568 ID atype = node->nd_next->nd_mid;
3569 LABEL *lfin = NEW_LABEL(nd_line(node));
3570 LABEL *lcfin = NEW_LABEL(nd_line(node));
3572 class C; attr_accessor :c; end
3573 r = C.new
3574 r.a &&= v # asgn2
3576 eval r # r
3577 dup # r r
3578 eval r.a # r o
3580 # or
3581 dup # r o o
3582 if lcfin # r o
3583 pop # r
3584 eval v # r v
3585 send a= # v
3586 jump lfin # v
3588 lcfin: # r o
3589 swap # o r
3590 pop # o
3592 lfin: # v
3594 # and
3595 dup # r o o
3596 unless lcfin
3597 pop # r
3598 eval v # r v
3599 send a= # v
3600 jump lfin # v
3602 # others
3603 eval v # r o v
3604 send ?? # r w
3605 send a= # w
3609 COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
3610 ADD_INSN(ret, nd_line(node), dup);
3611 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_vid),
3612 INT2FIX(0));
3614 if (atype == 0 || atype == 1) { /* 0: OR or 1: AND */
3615 ADD_INSN(ret, nd_line(node), dup);
3616 if (atype == 0) {
3617 ADD_INSNL(ret, nd_line(node), branchif, lcfin);
3619 else {
3620 ADD_INSNL(ret, nd_line(node), branchunless, lcfin);
3622 ADD_INSN(ret, nd_line(node), pop);
3623 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3624 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3625 INT2FIX(1));
3626 ADD_INSNL(ret, nd_line(node), jump, lfin);
3628 ADD_LABEL(ret, lcfin);
3629 ADD_INSN(ret, nd_line(node), swap);
3630 ADD_INSN(ret, nd_line(node), pop);
3632 ADD_LABEL(ret, lfin);
3634 else {
3635 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3636 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_mid),
3637 INT2FIX(1));
3638 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3639 INT2FIX(1));
3642 if (poped) {
3643 /* we can apply more optimize */
3644 ADD_INSN(ret, nd_line(node), pop);
3646 break;
3648 case NODE_OP_ASGN_AND:
3649 case NODE_OP_ASGN_OR:{
3650 LABEL *lfin = NEW_LABEL(nd_line(node));
3651 LABEL *lassign;
3653 if (nd_type(node) == NODE_OP_ASGN_OR) {
3654 LABEL *lfinish[2];
3655 lfinish[0] = lfin;
3656 lfinish[1] = 0;
3657 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
3658 lassign = lfinish[1];
3659 if (!lassign) {
3660 lassign = NEW_LABEL(nd_line(node));
3662 ADD_INSNL(ret, nd_line(node), branchunless, lassign);
3664 else {
3665 lassign = NEW_LABEL(nd_line(node));
3668 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
3669 ADD_INSN(ret, nd_line(node), dup);
3671 if (nd_type(node) == NODE_OP_ASGN_AND) {
3672 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
3674 else {
3675 ADD_INSNL(ret, nd_line(node), branchif, lfin);
3678 ADD_INSN(ret, nd_line(node), pop);
3679 ADD_LABEL(ret, lassign);
3680 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
3681 ADD_LABEL(ret, lfin);
3683 if (poped) {
3684 /* we can apply more optimize */
3685 ADD_INSN(ret, nd_line(node), pop);
3687 break;
3689 case NODE_CALL:
3690 case NODE_FCALL:
3691 case NODE_VCALL:{ /* VCALL: variable or call */
3693 call: obj.method(...)
3694 fcall: func(...)
3695 vcall: func
3697 DECL_ANCHOR(recv);
3698 DECL_ANCHOR(args);
3699 ID mid = node->nd_mid;
3700 VALUE argc;
3701 unsigned long flag = 0;
3702 VALUE parent_block = iseq->compile_data->current_block;
3703 iseq->compile_data->current_block = Qfalse;
3705 INIT_ANCHOR(recv);
3706 INIT_ANCHOR(args);
3707 #if SUPPORT_JOKE
3708 if (nd_type(node) == NODE_VCALL) {
3709 if (mid == idBitblt) {
3710 ADD_INSN(ret, nd_line(node), bitblt);
3711 break;
3713 else if (mid == idAnswer) {
3714 ADD_INSN(ret, nd_line(node), answer);
3715 break;
3718 /* only joke */
3720 static ID goto_id;
3721 static ID label_id;
3722 VALUE label;
3723 VALUE label_sym;
3725 if (goto_id == 0) {
3726 goto_id = rb_intern("__goto__");
3727 label_id = rb_intern("__label__");
3730 if (nd_type(node) == NODE_FCALL &&
3731 (mid == goto_id || mid == label_id)) {
3732 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
3733 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
3735 label_sym = label = node->nd_args->nd_head->nd_lit;
3736 if ((label =
3737 rb_hash_aref(iseq->compile_data,
3738 label_sym)) == Qnil) {
3739 rb_hash_aset(iseq->compile_data, label_sym,
3740 label = NEW_LABEL(nd_line(node)));
3743 else {
3744 rb_bug("invalid goto/label format");
3748 if (mid == goto_id) {
3749 ADD_INSNL(ret, nd_line(node), jump, label);
3751 else {
3752 ADD_LABEL(ret, label);
3754 break;
3757 #endif
3758 /* reciever */
3759 if (type == NODE_CALL) {
3760 COMPILE(recv, "recv", node->nd_recv);
3762 else if (type == NODE_FCALL || type == NODE_VCALL) {
3763 ADD_CALL_RECEIVER(recv, nd_line(node));
3766 /* args */
3767 if (nd_type(node) != NODE_VCALL) {
3768 argc = setup_args(iseq, args, node->nd_args, &flag);
3770 else {
3771 argc = INT2FIX(0);
3774 ADD_SEQ(ret, recv);
3775 ADD_SEQ(ret, args);
3777 debugp_param("call args argc", argc);
3778 debugp_param("call method", ID2SYM(mid));
3780 switch (nd_type(node)) {
3781 case NODE_VCALL:
3782 flag |= VM_CALL_VCALL_BIT;
3783 /* VCALL is funcall, so fall through */
3784 case NODE_FCALL:
3785 flag |= VM_CALL_FCALL_BIT;
3788 ADD_SEND_R(ret, nd_line(node), ID2SYM(mid),
3789 argc, parent_block, LONG2FIX(flag));
3791 if (poped) {
3792 ADD_INSN(ret, nd_line(node), pop);
3794 break;
3796 case NODE_SUPER:
3797 case NODE_ZSUPER:{
3798 DECL_ANCHOR(args);
3799 VALUE argc;
3800 unsigned long flag = 0;
3801 VALUE parent_block = iseq->compile_data->current_block;
3803 INIT_ANCHOR(args);
3804 iseq->compile_data->current_block = Qfalse;
3805 if (nd_type(node) == NODE_SUPER) {
3806 argc = setup_args(iseq, args, node->nd_args, &flag);
3808 else {
3809 /* NODE_ZSUPER */
3810 int i;
3811 rb_iseq_t *liseq = iseq->local_iseq;
3813 argc = INT2FIX(liseq->argc);
3815 /* normal arguments */
3816 for (i = 0; i < liseq->argc; i++) {
3817 int idx = liseq->local_size - i;
3818 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3821 if (!liseq->arg_simple) {
3822 if (liseq->arg_opts) {
3823 /* optional arguments */
3824 int j;
3825 for (j = 0; j < liseq->arg_opts - 1; j++) {
3826 int idx = liseq->local_size - (i + j);
3827 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3829 i += j;
3830 argc = INT2FIX(i);
3833 if (liseq->arg_rest != -1) {
3834 /* rest argument */
3835 int idx = liseq->local_size - liseq->arg_rest;
3836 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3837 argc = INT2FIX(liseq->arg_rest + 1);
3838 flag |= VM_CALL_ARGS_SPLAT_BIT;
3841 if (liseq->arg_post_len) {
3842 /* post arguments */
3843 int post_len = liseq->arg_post_len;
3844 int post_start = liseq->arg_post_start;
3846 if (liseq->arg_rest != -1) {
3847 int j;
3848 for (j=0; j<post_len; j++) {
3849 int idx = liseq->local_size - (post_start + j);
3850 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3852 ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j));
3853 ADD_INSN (args, nd_line(node), concatarray);
3854 /* argc is setteled at above */
3856 else {
3857 int j;
3858 for (j=0; j<post_len; j++) {
3859 int idx = liseq->local_size - (post_start + j);
3860 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3862 argc = INT2FIX(post_len + post_start);
3868 /* dummy reciever */
3869 ADD_INSN1(ret, nd_line(node), putobject,
3870 nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
3871 ADD_SEQ(ret, args);
3872 ADD_INSN3(ret, nd_line(node), invokesuper,
3873 argc, parent_block, LONG2FIX(flag));
3875 if (poped) {
3876 ADD_INSN(ret, nd_line(node), pop);
3878 break;
3880 case NODE_ARRAY:{
3881 compile_array_(iseq, ret, node, Qtrue, poped);
3882 break;
3884 case NODE_ZARRAY:{
3885 if (!poped) {
3886 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(0));
3888 break;
3890 case NODE_VALUES:{
3891 NODE *n = node;
3892 while (n) {
3893 COMPILE(ret, "values item", n->nd_head);
3894 n = n->nd_next;
3896 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(node->nd_alen));
3897 if (poped) {
3898 ADD_INSN(ret, nd_line(node), pop);
3900 break;
3902 case NODE_HASH:{
3903 DECL_ANCHOR(list);
3904 VALUE size = 0;
3905 int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
3907 INIT_ANCHOR(list);
3908 switch (type) {
3909 case NODE_ARRAY:{
3910 compile_array(iseq, list, node->nd_head, Qfalse);
3911 size = OPERAND_AT(POP_ELEMENT(list), 0);
3912 ADD_SEQ(ret, list);
3913 break;
3915 case NODE_ZARRAY:
3916 size = INT2FIX(0);
3917 break;
3919 default:
3920 rb_bug("can't make hash with this node: %s", ruby_node_name(type));
3923 ADD_INSN1(ret, nd_line(node), newhash, size);
3925 if (poped) {
3926 ADD_INSN(ret, nd_line(node), pop);
3928 break;
3930 case NODE_RETURN:{
3931 rb_iseq_t *is = iseq;
3933 while (is) {
3934 if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) {
3935 COMPILE_ERROR((ERROR_ARGS "Invalid return"));
3936 break;
3938 else {
3939 LABEL *splabel = 0;
3941 if (is->type == ISEQ_TYPE_METHOD) {
3942 splabel = NEW_LABEL(0);
3943 ADD_LABEL(ret, splabel);
3944 ADD_ADJUST(ret, nd_line(node), 0);
3947 COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
3949 if (is->type == ISEQ_TYPE_METHOD) {
3950 add_ensure_iseq(ret, iseq);
3951 ADD_INSN(ret, nd_line(node), leave);
3952 ADD_ADJUST_RESTORE(ret, splabel);
3954 if (!poped) {
3955 ADD_INSN(ret, nd_line(node), putnil);
3958 else {
3959 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x01) /* TAG_RETURN */ );
3960 if (poped) {
3961 ADD_INSN(ret, nd_line(node), pop);
3964 break;
3967 break;
3969 case NODE_YIELD:{
3970 DECL_ANCHOR(args);
3971 VALUE argc;
3972 unsigned long flag = 0;
3974 INIT_ANCHOR(args);
3975 if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) {
3976 COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
3979 if (node->nd_head) {
3980 argc = setup_args(iseq, args, node->nd_head, &flag);
3982 else {
3983 argc = INT2FIX(0);
3986 ADD_SEQ(ret, args);
3987 ADD_INSN2(ret, nd_line(node), invokeblock, argc, LONG2FIX(flag));
3989 if (poped) {
3990 ADD_INSN(ret, nd_line(node), pop);
3992 break;
3994 case NODE_LVAR:{
3995 if (!poped) {
3996 ID id = node->nd_vid;
3997 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3999 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
4000 ADD_INSN1(ret, nd_line(node), getlocal, INT2FIX(idx));
4002 break;
4004 case NODE_DVAR:{
4005 int lv, idx, ls;
4006 debugi("nd_vid", node->nd_vid);
4007 if (!poped) {
4008 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
4009 if (idx < 0) {
4010 rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
4012 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(ls - idx),
4013 INT2FIX(lv));
4015 break;
4017 case NODE_GVAR:{
4018 ADD_INSN1(ret, nd_line(node), getglobal,
4019 (((long)node->nd_entry) | 1));
4020 if (poped) {
4021 ADD_INSN(ret, nd_line(node), pop);
4023 break;
4025 case NODE_IVAR:{
4026 debugi("nd_vid", node->nd_vid);
4027 if (!poped) {
4028 ADD_INSN1(ret, nd_line(node), getinstancevariable,
4029 ID2SYM(node->nd_vid));
4031 break;
4033 case NODE_CONST:{
4034 debugi("nd_vid", node->nd_vid);
4036 if (iseq->compile_data->option->inline_const_cache) {
4037 LABEL *lstart = NEW_LABEL(nd_line(node));
4038 LABEL *lend = NEW_LABEL(nd_line(node));
4040 ADD_LABEL(ret, lstart);
4041 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4042 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4043 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4044 ADD_LABEL(ret, lend);
4046 else {
4047 ADD_INSN(ret, nd_line(node), putnil);
4048 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4051 if (poped) {
4052 ADD_INSN(ret, nd_line(node), pop);
4054 break;
4056 case NODE_CVAR:{
4057 if (!poped) {
4058 ADD_INSN1(ret, nd_line(node), getclassvariable,
4059 ID2SYM(node->nd_vid));
4061 break;
4063 case NODE_NTH_REF:{
4064 if (!poped) {
4065 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4066 INT2FIX(node->nd_nth << 1));
4068 break;
4070 case NODE_BACK_REF:{
4071 if (!poped) {
4072 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4073 INT2FIX(0x01 | (node->nd_nth << 1)));
4075 break;
4077 case NODE_MATCH:
4078 case NODE_MATCH2:
4079 case NODE_MATCH3:{
4080 DECL_ANCHOR(recv);
4081 DECL_ANCHOR(val);
4083 INIT_ANCHOR(recv);
4084 INIT_ANCHOR(val);
4085 switch(nd_type(node)) {
4086 case NODE_MATCH:
4087 ADD_INSN1(recv, nd_line(node), putobject, node->nd_lit);
4088 ADD_INSN2(val, nd_line(node), getspecial, INT2FIX(0),
4089 INT2FIX(0));
4090 break;
4091 case NODE_MATCH2:
4092 COMPILE(recv, "reciever", node->nd_recv);
4093 COMPILE(val, "value", node->nd_value);
4094 break;
4095 case NODE_MATCH3:
4096 COMPILE(recv, "reciever", node->nd_value);
4097 COMPILE(val, "value", node->nd_recv);
4098 break;
4101 if (iseq->compile_data->option->specialized_instruction) {
4102 /* TODO: detect by node */
4103 if (recv->last == recv->anchor.next &&
4104 INSN_OF(recv->last) == BIN(putobject) &&
4105 nd_type(node) == NODE_MATCH2) {
4106 ADD_SEQ(ret, val);
4107 ADD_INSN1(ret, nd_line(node), opt_regexpmatch1,
4108 OPERAND_AT(recv->last, 0));
4110 else {
4111 ADD_SEQ(ret, recv);
4112 ADD_SEQ(ret, val);
4113 ADD_INSN(ret, nd_line(node), opt_regexpmatch2);
4116 else {
4117 ADD_SEQ(ret, recv);
4118 ADD_SEQ(ret, val);
4119 ADD_SEND(ret, nd_line(node), ID2SYM(idEqTilde), INT2FIX(1));
4122 if (poped) {
4123 ADD_INSN(ret, nd_line(node), pop);
4125 break;
4127 case NODE_LIT:{
4128 debugp_param("lit", node->nd_lit);
4129 if (!poped) {
4130 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4132 break;
4134 case NODE_STR:{
4135 debugp_param("nd_lit", node->nd_lit);
4136 if (!poped) {
4137 ADD_INSN1(ret, nd_line(node), putstring, node->nd_lit);
4139 break;
4141 case NODE_DSTR:{
4142 compile_dstr(iseq, ret, node);
4144 if (poped) {
4145 ADD_INSN(ret, nd_line(node), pop);
4147 break;
4149 case NODE_XSTR:{
4150 ADD_CALL_RECEIVER(ret, nd_line(node));
4151 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4152 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4154 if (poped) {
4155 ADD_INSN(ret, nd_line(node), pop);
4157 break;
4159 case NODE_DXSTR:{
4160 ADD_CALL_RECEIVER(ret, nd_line(node));
4161 compile_dstr(iseq, ret, node);
4162 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4164 if (poped) {
4165 ADD_INSN(ret, nd_line(node), pop);
4167 break;
4169 case NODE_EVSTR:{
4170 COMPILE(ret, "nd_body", node->nd_body);
4172 if (poped) {
4173 ADD_INSN(ret, nd_line(node), pop);
4175 else {
4176 ADD_INSN(ret, nd_line(node), tostring);
4178 break;
4180 case NODE_DREGX:{
4181 compile_dregx(iseq, ret, node);
4183 if (poped) {
4184 ADD_INSN(ret, nd_line(node), pop);
4186 break;
4188 case NODE_DREGX_ONCE:{
4189 /* TODO: once? */
4190 LABEL *lstart = NEW_LABEL(nd_line(node));
4191 LABEL *lend = NEW_LABEL(nd_line(node));
4193 ADD_LABEL(ret, lstart);
4194 ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend);
4195 ADD_INSN(ret, nd_line(node), pop);
4197 compile_dregx(iseq, ret, node);
4199 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4200 ADD_LABEL(ret, lend);
4202 if (poped) {
4203 ADD_INSN(ret, nd_line(node), pop);
4205 break;
4207 case NODE_ARGSCAT:{
4208 COMPILE(ret, "argscat head", node->nd_head);
4209 COMPILE(ret, "argscat body", node->nd_body);
4210 ADD_INSN(ret, nd_line(node), concatarray);
4211 break;
4213 case NODE_ARGSPUSH:{
4214 COMPILE(ret, "arsgpush head", node->nd_head);
4215 COMPILE(ret, "argspush body", node->nd_body);
4216 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
4217 ADD_INSN(ret, nd_line(node), concatarray);
4218 break;
4220 case NODE_SPLAT:{
4221 COMPILE(ret, "splat", node->nd_head);
4222 ADD_INSN1(ret, nd_line(node), splatarray, Qfalse);
4224 if (poped) {
4225 ADD_INSN(ret, nd_line(node), pop);
4227 break;
4229 case NODE_DEFN:{
4230 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4231 rb_str_dup(rb_id2str(node->nd_mid)),
4232 ISEQ_TYPE_METHOD);
4234 debugp_param("defn/iseq", iseqval);
4236 ADD_INSN (ret, nd_line(node), putnil);
4237 ADD_INSN3(ret, nd_line(node), definemethod,
4238 ID2SYM(node->nd_mid), iseqval, INT2FIX(0));
4239 if (!poped) {
4240 ADD_INSN(ret, nd_line(node), putnil);
4242 debugp_param("defn", iseqval);
4243 break;
4245 case NODE_DEFS:{
4246 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4247 rb_str_dup(rb_id2str(node->nd_mid)),
4248 ISEQ_TYPE_METHOD);
4250 debugp_param("defs/iseq", iseqval);
4252 COMPILE(ret, "defs: recv", node->nd_recv);
4253 ADD_INSN3(ret, nd_line(node), definemethod,
4254 ID2SYM(node->nd_mid), iseqval, INT2FIX(1));
4255 if (!poped) {
4256 ADD_INSN(ret, nd_line(node), putnil);
4258 break;
4260 case NODE_ALIAS:{
4261 COMPILE(ret, "alias arg1", node->u1.node);
4262 COMPILE(ret, "alias arg2", node->u2.node);
4264 ADD_INSN1(ret, nd_line(node), alias, Qfalse);
4266 if (!poped) {
4267 ADD_INSN(ret, nd_line(node), putnil);
4269 break;
4271 case NODE_VALIAS:{
4272 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id));
4273 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id));
4274 ADD_INSN1(ret, nd_line(node), alias, Qtrue);
4276 if (!poped) {
4277 ADD_INSN(ret, nd_line(node), putnil);
4279 break;
4281 case NODE_UNDEF:{
4282 COMPILE(ret, "undef arg", node->u2.node);
4283 ADD_INSN(ret, nd_line(node), undef);
4285 if (!poped) {
4286 ADD_INSN(ret, nd_line(node), putnil);
4288 break;
4290 case NODE_CLASS:{
4291 VALUE iseqval =
4292 NEW_CHILD_ISEQVAL(
4293 node->nd_body,
4294 rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4295 ISEQ_TYPE_CLASS);
4296 compile_cpath(ret, iseq, node->nd_cpath);
4297 COMPILE(ret, "super", node->nd_super);
4298 ADD_INSN3(ret, nd_line(node), defineclass,
4299 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(0));
4301 if (poped) {
4302 ADD_INSN(ret, nd_line(node), pop);
4304 break;
4306 case NODE_MODULE:{
4307 VALUE iseqval = NEW_CHILD_ISEQVAL(
4308 node->nd_body,
4309 rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4310 ISEQ_TYPE_CLASS);
4312 COMPILE(ret, "mbase", node->nd_cpath->nd_head);
4313 ADD_INSN (ret, nd_line(node), putnil); /* dummy */
4314 ADD_INSN3(ret, nd_line(node), defineclass,
4315 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2));
4316 if (poped) {
4317 ADD_INSN(ret, nd_line(node), pop);
4319 break;
4321 case NODE_SCLASS:{
4322 VALUE iseqval =
4323 NEW_ISEQVAL(node->nd_body, rb_str_new2("singletonclass"),
4324 ISEQ_TYPE_CLASS);
4326 COMPILE(ret, "sclass#recv", node->nd_recv);
4327 ADD_INSN (ret, nd_line(node), putnil);
4328 ADD_INSN3(ret, nd_line(node), defineclass,
4329 ID2SYM(rb_intern("singletonclass")), iseqval, INT2FIX(1));
4331 if (poped) {
4332 ADD_INSN(ret, nd_line(node), pop);
4334 break;
4336 case NODE_COLON2:{
4337 if (rb_is_const_id(node->nd_mid)) {
4338 /* constant */
4339 LABEL *lstart = NEW_LABEL(nd_line(node));
4340 LABEL *lend = NEW_LABEL(nd_line(node));
4341 DECL_ANCHOR(pref);
4342 DECL_ANCHOR(body);
4344 INIT_ANCHOR(pref);
4345 INIT_ANCHOR(body);
4346 compile_colon2(iseq, node, pref, body);
4347 if (LIST_SIZE_ZERO(pref)) {
4348 if (iseq->compile_data->option->inline_const_cache) {
4349 ADD_LABEL(ret, lstart);
4350 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4352 else {
4353 ADD_INSN(ret, nd_line(node), putnil);
4356 ADD_SEQ(ret, body);
4358 if (iseq->compile_data->option->inline_const_cache) {
4359 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4360 ADD_LABEL(ret, lend);
4363 else {
4364 ADD_SEQ(ret, pref);
4365 ADD_SEQ(ret, body);
4368 else {
4369 /* function call */
4370 ADD_CALL_RECEIVER(ret, nd_line(node));
4371 COMPILE(ret, "colon2#nd_head", node->nd_head);
4372 ADD_CALL(ret, nd_line(node), ID2SYM(node->nd_mid),
4373 INT2FIX(1));
4375 if (poped) {
4376 ADD_INSN(ret, nd_line(node), pop);
4378 break;
4380 case NODE_COLON3:{
4381 LABEL *lstart = NEW_LABEL(nd_line(node));
4382 LABEL *lend = NEW_LABEL(nd_line(node));
4383 debugi("colon3#nd_mid", node->nd_mid);
4385 /* add cache insn */
4386 if (iseq->compile_data->option->inline_const_cache) {
4387 ADD_LABEL(ret, lstart);
4388 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4389 ADD_INSN(ret, nd_line(node), pop);
4392 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
4393 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4395 if (iseq->compile_data->option->inline_const_cache) {
4396 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4397 ADD_LABEL(ret, lend);
4400 if (poped) {
4401 ADD_INSN(ret, nd_line(node), pop);
4403 break;
4405 case NODE_DOT2:
4406 case NODE_DOT3:{
4407 int flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
4408 COMPILE(ret, "min", (NODE *) node->nd_beg);
4409 COMPILE(ret, "max", (NODE *) node->nd_end);
4410 if (poped) {
4411 ADD_INSN(ret, nd_line(node), pop);
4412 ADD_INSN(ret, nd_line(node), pop);
4414 else {
4415 ADD_INSN1(ret, nd_line(node), newrange, flag);
4417 break;
4419 case NODE_FLIP2:
4420 case NODE_FLIP3:{
4421 LABEL *lend = NEW_LABEL(nd_line(node));
4422 LABEL *lfin = NEW_LABEL(nd_line(node));
4423 LABEL *ltrue = NEW_LABEL(nd_line(node));
4424 VALUE key = rb_sprintf("flipflag/%s-%p-%d",
4425 RSTRING_PTR(iseq->name), iseq,
4426 iseq->compile_data->flip_cnt++);
4428 iseq_add_mark_object_compile_time(iseq, key);
4429 ADD_INSN2(ret, nd_line(node), getspecial, key, INT2FIX(0));
4430 ADD_INSNL(ret, nd_line(node), branchif, lend);
4432 /* *flip == 0 */
4433 COMPILE(ret, "flip2 beg", node->nd_beg);
4434 ADD_INSN(ret, nd_line(node), dup);
4435 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
4436 if (nd_type(node) == NODE_FLIP3) {
4437 ADD_INSN(ret, nd_line(node), dup);
4438 ADD_INSN1(ret, nd_line(node), setspecial, key);
4439 ADD_INSNL(ret, nd_line(node), jump, lfin);
4441 else {
4442 ADD_INSN1(ret, nd_line(node), setspecial, key);
4445 /* *flip == 1 */
4446 ADD_LABEL(ret, lend);
4447 COMPILE(ret, "flip2 end", node->nd_end);
4448 ADD_INSNL(ret, nd_line(node), branchunless, ltrue);
4449 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4450 ADD_INSN1(ret, nd_line(node), setspecial, key);
4452 ADD_LABEL(ret, ltrue);
4453 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4455 ADD_LABEL(ret, lfin);
4456 break;
4458 case NODE_SELF:{
4459 if (!poped) {
4460 ADD_INSN(ret, nd_line(node), putself);
4462 break;
4464 case NODE_NIL:{
4465 if (!poped) {
4466 ADD_INSN(ret, nd_line(node), putnil);
4468 break;
4470 case NODE_TRUE:{
4471 if (!poped) {
4472 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4474 break;
4476 case NODE_FALSE:{
4477 if (!poped) {
4478 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4480 break;
4482 case NODE_ERRINFO:{
4483 if (!poped) {
4484 if (iseq->type == ISEQ_TYPE_RESCUE) {
4485 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
4486 INT2FIX(0));
4488 else {
4489 rb_iseq_t *ip = iseq;
4490 int level = 0;
4491 while (ip) {
4492 if (ip->type == ISEQ_TYPE_RESCUE) {
4493 break;
4495 ip = ip->parent_iseq;
4496 level++;
4498 if (ip) {
4499 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
4500 INT2FIX(level));
4502 else {
4503 ADD_INSN(ret, nd_line(node), putnil);
4507 break;
4509 case NODE_DEFINED:{
4510 if (!poped) {
4511 LABEL *lfinish[2];
4512 lfinish[0] = NEW_LABEL(nd_line(node));
4513 lfinish[1] = 0;
4514 defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
4515 if (lfinish[1]) {
4516 ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
4517 ADD_LABEL(ret, lfinish[1]);
4518 ADD_INSN(ret, nd_line(node), putnil);
4520 ADD_LABEL(ret, lfinish[0]);
4522 break;
4524 case NODE_POSTEXE:{
4525 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4526 ADD_INSN1(ret, nd_line(node), postexe, block);
4527 if (!poped) {
4528 ADD_INSN(ret, nd_line(node), putnil);
4530 break;
4532 case NODE_DSYM:{
4533 compile_dstr(iseq, ret, node);
4534 if (!poped) {
4535 ADD_SEND(ret, nd_line(node), ID2SYM(idIntern), INT2FIX(0));
4537 else {
4538 ADD_INSN(ret, nd_line(node), pop);
4540 break;
4542 case NODE_ATTRASGN:{
4543 DECL_ANCHOR(recv);
4544 DECL_ANCHOR(args);
4545 unsigned long flag = 0;
4546 VALUE argc;
4548 INIT_ANCHOR(recv);
4549 INIT_ANCHOR(args);
4550 argc = setup_args(iseq, args, node->nd_args, &flag);
4552 if (node->nd_recv == (NODE *) 1) {
4553 flag |= VM_CALL_FCALL_BIT;
4554 ADD_INSN(recv, nd_line(node), putself);
4556 else {
4557 COMPILE(recv, "recv", node->nd_recv);
4560 debugp_param("argc", argc);
4561 debugp_param("nd_mid", ID2SYM(node->nd_mid));
4563 if (!poped) {
4564 ADD_INSN(ret, nd_line(node), putnil);
4565 ADD_SEQ(ret, recv);
4566 ADD_SEQ(ret, args);
4568 if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
4569 ADD_INSN1(ret, nd_line(node), topn, INT2FIX(1));
4570 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 3));
4571 ADD_INSN (ret, nd_line(node), pop);
4573 else {
4574 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 1));
4577 else {
4578 ADD_SEQ(ret, recv);
4579 ADD_SEQ(ret, args);
4581 ADD_SEND_R(ret, nd_line(node), ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
4582 ADD_INSN(ret, nd_line(node), pop);
4584 break;
4586 case NODE_OPTBLOCK:{
4587 /* for optimize */
4588 LABEL *redo_label = NEW_LABEL(0);
4589 LABEL *next_label = NEW_LABEL(0);
4591 iseq->compile_data->start_label = next_label;
4592 iseq->compile_data->redo_label = redo_label;
4594 ADD_LABEL(ret, redo_label);
4595 COMPILE_(ret, "optblock body", node->nd_head, 1 /* pop */ );
4596 ADD_LABEL(ret, next_label);
4597 ADD_INSN(ret, 0, opt_checkenv);
4598 break;
4600 case NODE_PRELUDE:{
4601 COMPILE_POPED(ret, "prelude", node->nd_head);
4602 COMPILE_(ret, "body", node->nd_body, poped);
4603 break;
4605 case NODE_LAMBDA:{
4606 /* compile same as lambda{...} */
4607 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4608 VALUE argc = INT2FIX(0);
4609 ADD_CALL_RECEIVER(ret, nd_line(node));
4610 ADD_CALL_WITH_BLOCK(ret, nd_line(node), ID2SYM(idLambda), argc, block);
4612 if (poped) {
4613 ADD_INSN(ret, nd_line(node), pop);
4615 break;
4617 default:
4618 rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
4619 return Qnil;
4622 debug_node_end();
4623 return COMPILE_OK;
4626 /***************************/
4627 /* instruction information */
4628 /***************************/
4630 static int
4631 insn_data_length(INSN *iobj)
4633 return insn_len(iobj->insn_id);
4636 static int
4637 calc_sp_depth(int depth, INSN *insn)
4639 return insn_stack_increase(depth, insn->insn_id, insn->operands);
4642 static int
4643 insn_data_line_no(INSN *iobj)
4645 return insn_len(iobj->line_no);
4648 static VALUE
4649 insn_data_to_s_detail(INSN *iobj)
4651 VALUE str = rb_str_new(0, 0);
4653 str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
4654 if (iobj->operands) {
4655 const char *types = insn_op_types(iobj->insn_id);
4656 int j;
4658 for (j = 0; types[j]; j++) {
4659 char type = types[j];
4661 switch (type) {
4662 case TS_OFFSET: /* label(destination position) */
4664 char buff[0x100];
4665 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
4666 snprintf(buff, sizeof(buff), "<L%03d>", lobj->label_no);
4667 rb_str_concat(str, rb_str_new2(buff));
4668 break;
4670 break;
4671 case TS_ISEQ: /* iseq */
4673 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
4674 VALUE val = Qnil;
4675 if (iseq) {
4676 val = iseq->self;
4678 rb_str_concat(str, rb_inspect(val));
4680 break;
4681 case TS_LINDEX:
4682 case TS_DINDEX:
4683 case TS_NUM: /* ulong */
4684 case TS_VALUE: /* VALUE */
4685 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4686 break;
4687 case TS_ID: /* ID */
4688 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4689 break;
4690 case TS_GENTRY:
4692 struct global_entry *entry = (struct global_entry *)
4693 (OPERAND_AT(iobj, j) & (~1));
4694 rb_str_cat2(str, rb_id2name(entry->id));
4696 case TS_IC: /* method cache */
4697 rb_str_cat2(str, "<ic>");
4698 break;
4699 case TS_CDHASH: /* case/when condition cache */
4700 rb_str_cat2(str, "<ch>");
4701 break;
4702 default:{
4703 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
4706 if (types[j + 1]) {
4707 rb_str_cat2(str, ", ");
4711 return str;
4714 static void
4715 dump_disasm_list(struct iseq_link_element *link)
4717 int pos = 0;
4718 INSN *iobj;
4719 LABEL *lobj;
4720 VALUE str;
4722 printf("-- raw disasm--------\n");
4724 while (link) {
4725 switch (link->type) {
4726 case ISEQ_ELEMENT_INSN:
4728 iobj = (INSN *)link;
4729 str = insn_data_to_s_detail(iobj);
4730 printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str),
4731 insn_data_line_no(iobj));
4732 pos += insn_data_length(iobj);
4733 break;
4735 case ISEQ_ELEMENT_LABEL:
4737 lobj = (LABEL *)link;
4738 printf("<L%03d>\n", lobj->label_no);
4739 break;
4741 case ISEQ_ELEMENT_NONE:
4743 printf("[none]\n");
4744 break;
4746 case ISEQ_ELEMENT_ADJUST:
4748 ADJUST *adjust = (ADJUST *)link;
4749 printf("adjust: [label: %d]\n", adjust->label->label_no);
4750 break;
4752 default:
4753 /* ignore */
4754 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
4756 link = link->next;
4758 printf("---------------------\n");
4761 VALUE
4762 insns_name_array(void)
4764 VALUE ary = rb_ary_new();
4765 int i;
4766 for (i = 0; i < sizeof(insn_name_info) / sizeof(insn_name_info[0]); i++) {
4767 rb_ary_push(ary, rb_str_new2(insn_name_info[i]));
4769 return ary;
4772 static LABEL *
4773 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
4775 LABEL *label = 0;
4776 st_data_t tmp;
4777 obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
4779 if (st_lookup(labels_table, obj, &tmp) == 0) {
4780 label = NEW_LABEL(0);
4781 st_insert(labels_table, obj, (st_data_t)label);
4783 else {
4784 label = (LABEL *)tmp;
4786 return label;
4789 static VALUE
4790 get_exception_sym2type(VALUE sym)
4792 static VALUE symRescue, symEnsure, symRetry;
4793 static VALUE symBreak, symRedo, symNext;
4795 if (symRescue == 0) {
4796 symRescue = ID2SYM(rb_intern("rescue"));
4797 symEnsure = ID2SYM(rb_intern("ensure"));
4798 symRetry = ID2SYM(rb_intern("retry"));
4799 symBreak = ID2SYM(rb_intern("break"));
4800 symRedo = ID2SYM(rb_intern("redo"));
4801 symNext = ID2SYM(rb_intern("next"));
4804 if (sym == symRescue) return CATCH_TYPE_RESCUE;
4805 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
4806 if (sym == symRetry) return CATCH_TYPE_RETRY;
4807 if (sym == symBreak) return CATCH_TYPE_BREAK;
4808 if (sym == symRedo) return CATCH_TYPE_REDO;
4809 if (sym == symNext) return CATCH_TYPE_NEXT;
4810 rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
4811 RSTRING_PTR(rb_inspect(sym)));
4812 return 0;
4815 static int
4816 iseq_build_exception(rb_iseq_t *iseq, struct st_table *labels_table,
4817 VALUE exception)
4819 int i;
4821 for (i=0; i<RARRAY_LEN(exception); i++) {
4822 VALUE v, type, *ptr, eiseqval;
4823 LABEL *lstart, *lend, *lcont;
4824 int sp;
4826 RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
4827 "Array", "to_ary");
4828 if (RARRAY_LEN(v) != 6) {
4829 rb_raise(rb_eSyntaxError, "wrong exception entry");
4831 ptr = RARRAY_PTR(v);
4832 type = get_exception_sym2type(ptr[0]);
4833 if (ptr[1] == Qnil) {
4834 eiseqval = 0;
4836 else {
4837 eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil);
4840 lstart = register_label(iseq, labels_table, ptr[2]);
4841 lend = register_label(iseq, labels_table, ptr[3]);
4842 lcont = register_label(iseq, labels_table, ptr[4]);
4843 sp = NUM2INT(ptr[5]);
4845 ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
4847 return COMPILE_OK;
4850 struct st_table *insn_make_insn_table(void);
4852 static int
4853 iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
4854 VALUE body, struct st_table *labels_table)
4856 /* TODO: body should be freezed */
4857 VALUE *ptr = RARRAY_PTR(body);
4858 int len = RARRAY_LEN(body);
4859 int i, j;
4860 int line_no = 0;
4862 * index -> LABEL *label
4864 static struct st_table *insn_table;
4866 if (insn_table == 0) {
4867 insn_table = insn_make_insn_table();
4870 for (i=0; i<len; i++) {
4871 VALUE obj = ptr[i];
4873 if (SYMBOL_P(obj)) {
4874 LABEL *label = register_label(iseq, labels_table, obj);
4875 ADD_LABEL(anchor, label);
4877 else if (FIXNUM_P(obj)) {
4878 line_no = NUM2INT(obj);
4880 else if (TYPE(obj) == T_ARRAY) {
4881 VALUE *argv = 0;
4882 int argc = RARRAY_LEN(obj) - 1;
4883 VALUE insn_id;
4884 VALUE insn;
4886 insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
4887 if (st_lookup(insn_table, insn, &insn_id) == 0) {
4888 /* TODO: exception */
4889 RB_GC_GUARD(insn) = rb_inspect(insn);
4890 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4891 "unknown instruction: %s", RSTRING_PTR(insn));
4894 if (argc != insn_len(insn_id)-1) {
4895 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4896 "operand size mismatch");
4899 if (argc > 0) {
4900 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
4901 for (j=0; j<argc; j++) {
4902 VALUE op = rb_ary_entry(obj, j+1);
4903 switch (insn_op_type(insn_id, j)) {
4904 case TS_OFFSET: {
4905 LABEL *label = register_label(iseq, labels_table, op);
4906 argv[j] = (VALUE)label;
4907 break;
4909 case TS_LINDEX:
4910 case TS_DINDEX:
4911 case TS_NUM:
4912 argv[j] = (NUM2INT(op), op);
4913 break;
4914 case TS_VALUE:
4915 argv[j] = op;
4916 iseq_add_mark_object(iseq, op);
4917 break;
4918 case TS_ISEQ:
4920 if (op != Qnil) {
4921 if (TYPE(op) == T_ARRAY) {
4922 argv[j] = iseq_load(0, op, iseq->self, Qnil);
4924 else if (CLASS_OF(op) == rb_cISeq) {
4925 argv[j] = op;
4927 else {
4928 rb_raise(rb_eSyntaxError, "ISEQ is required");
4930 iseq_add_mark_object(iseq, argv[j]);
4932 else {
4933 argv[j] = 0;
4936 break;
4937 case TS_GENTRY:
4938 op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
4939 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
4940 break;
4941 case TS_IC:
4942 argv[j] = (VALUE)NEW_INLINE_CACHE_ENTRY();
4943 iseq_add_mark_object(iseq, argv[j]);
4944 break;
4945 case TS_ID:
4946 argv[j] = rb_convert_type(op, T_SYMBOL,
4947 "Symbol", "to_sym");
4948 break;
4949 case TS_CDHASH:
4951 int i;
4952 op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
4953 for (i=0; i<RARRAY_LEN(op); i+=2) {
4954 VALUE sym = rb_ary_entry(op, i+1);
4955 LABEL *label =
4956 register_label(iseq, labels_table, sym);
4957 rb_ary_store(op, i+1, (VALUE)label | 1);
4959 argv[j] = op;
4961 break;
4962 default:
4963 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type(insn_id, j));
4967 ADD_ELEM(anchor,
4968 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
4969 insn_id, argc, argv));
4971 else {
4972 rb_raise(rb_eTypeError, "unexpected object for instruction");
4975 st_free_table(labels_table);
4976 iseq_setup(iseq, anchor);
4977 return COMPILE_OK;
4980 #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
4981 #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
4982 #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
4983 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
4985 VALUE
4986 iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
4987 VALUE exception, VALUE body)
4989 int i;
4990 int opt = 0;
4991 ID *tbl;
4992 struct st_table *labels_table = st_init_numtable();
4994 DECL_ANCHOR(anchor);
4996 INIT_ANCHOR(anchor);
4997 if (iseq->type == ISEQ_TYPE_METHOD ||
4998 iseq->type == ISEQ_TYPE_TOP ||
4999 iseq->type == ISEQ_TYPE_CLASS) {
5000 opt = 1;
5003 iseq->local_table_size = opt + RARRAY_LEN(locals);
5004 iseq->local_table = tbl = (ID *)ALLOC_N(ID *, iseq->local_table_size);
5005 iseq->local_size = opt + iseq->local_table_size;
5007 for (i=0; i<RARRAY_LEN(locals); i++) {
5008 VALUE lv = RARRAY_PTR(locals)[i];
5009 tbl[i] = FIXNUM_P(lv) ? FIX2INT(lv) : SYM2ID(CHECK_SYMBOL(lv));
5012 /* args */
5013 if (FIXNUM_P(args)) {
5014 iseq->arg_size = iseq->argc = FIX2INT(args);
5015 iseq->arg_simple = 1;
5017 else {
5018 int i = 0;
5019 VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
5020 VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
5021 VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
5022 VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
5023 VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
5024 VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
5025 VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
5027 iseq->argc = FIX2INT(argc);
5028 iseq->arg_rest = FIX2INT(arg_rest);
5029 iseq->arg_post_len = FIX2INT(arg_post_len);
5030 iseq->arg_post_start = FIX2INT(arg_post_start);
5031 iseq->arg_block = FIX2INT(arg_block);
5032 iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, RARRAY_LEN(arg_opt_labels));
5034 if (iseq->arg_block != -1) {
5035 iseq->arg_size = iseq->arg_block + 1;
5037 else if (iseq->arg_post_len) {
5038 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
5040 else if (iseq->arg_rest != -1) {
5041 iseq->arg_size = iseq->arg_rest + 1;
5043 else {
5044 iseq->arg_size = iseq->argc + iseq->arg_opts;
5047 for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
5048 iseq->arg_opt_table[i] =
5049 (VALUE)register_label(iseq, labels_table,
5050 rb_ary_entry(arg_opt_labels, i));
5053 iseq->arg_simple = NUM2INT(arg_simple);
5056 /* exception */
5057 iseq_build_exception(iseq, labels_table, exception);
5059 /* body */
5060 iseq_build_body(iseq, anchor, body, labels_table);
5061 return iseq->self;