* enc/depend: transcode table generation depends on
[ruby-svn.git] / compile.c
blob993ebd082daaef6c30bc9482e63cbf1ec4d75ed9
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 VALUE iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt);
31 /* types */
33 typedef struct iseq_link_element {
34 enum {
35 ISEQ_ELEMENT_NONE = INT2FIX(0x00),
36 ISEQ_ELEMENT_LABEL = INT2FIX(0x01),
37 ISEQ_ELEMENT_INSN = INT2FIX(0x02),
38 ISEQ_ELEMENT_ADJUST = INT2FIX(0x03)
39 } type;
40 struct iseq_link_element *next;
41 struct iseq_link_element *prev;
42 } LINK_ELEMENT;
44 typedef struct iseq_link_anchor {
45 LINK_ELEMENT anchor;
46 LINK_ELEMENT *last;
47 } LINK_ANCHOR;
49 typedef struct iseq_label_data {
50 LINK_ELEMENT link;
51 int label_no;
52 int position;
53 int sc_state;
54 int set;
55 int sp;
56 } LABEL;
58 typedef struct iseq_insn_data {
59 LINK_ELEMENT link;
60 enum ruby_vminsn_type insn_id;
61 int line_no;
62 int operand_size;
63 int sc_state;
64 VALUE *operands;
65 } INSN;
67 typedef struct iseq_adjust_data {
68 LINK_ELEMENT link;
69 LABEL *label;
70 int line_no;
71 } ADJUST;
73 struct ensure_range {
74 LABEL *begin;
75 LABEL *end;
76 struct ensure_range *next;
79 struct iseq_compile_data_ensure_node_stack {
80 NODE *ensure_node;
81 struct iseq_compile_data_ensure_node_stack *prev;
82 struct ensure_range *erange;
85 #include "optinsn.inc"
86 #if OPT_INSTRUCTIONS_UNIFICATION
87 #include "optunifs.inc"
88 #endif
90 /* for debug */
91 #if CPDEBUG < 0
92 #define ISEQ_ARG iseq,
93 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
94 #else
95 #define ISEQ_ARG
96 #define ISEQ_ARG_DECLARE
97 #endif
99 #if CPDEBUG
100 #define gl_node_level iseq->compile_data->node_level
101 #if 0
102 static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor);
103 #endif
104 #endif
106 static void dump_disasm_list(LINK_ELEMENT *elem);
108 static int insn_data_length(INSN *iobj);
109 static int insn_data_line_no(INSN *iobj);
110 static int calc_sp_depth(int depth, INSN *iobj);
112 static void ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem);
114 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...);
115 static LABEL *new_label_body(rb_iseq_t *iseq, int line);
116 static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
118 static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int);
119 static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
120 static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
121 static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
123 static int iseq_set_local_table(rb_iseq_t *iseq, ID *tbl);
124 static int iseq_set_exception_local_table(rb_iseq_t *iseq);
125 static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node);
127 static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
128 static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
129 static int iseq_set_exception_table(rb_iseq_t *iseq);
130 static int iseq_set_optargs_table(rb_iseq_t *iseq);
133 * To make Array to LinkedList, use link_anchor
136 static void
137 verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *anchor)
139 #if CPDEBUG
140 int flag = 0;
141 LINK_ELEMENT *list, *plist;
143 if (!compile_debug) return;
145 list = anchor->anchor.next;
146 plist = &anchor->anchor;
147 while (list) {
148 if (plist != list->prev) {
149 flag += 1;
151 plist = list;
152 list = list->next;
155 if (anchor->last != plist && anchor->last != 0) {
156 flag |= 0x70000;
159 if (flag != 0) {
160 rb_bug("list verify error: %08x (%s)", flag, info);
162 #endif
164 #if CPDEBUG < 0
165 #define verify_list(info, anchor) verify_list(iseq, info, anchor)
166 #endif
169 * elem1, elem2 => elem1, elem2, elem
171 static void
172 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
174 elem->prev = anchor->last;
175 anchor->last->next = elem;
176 anchor->last = elem;
177 verify_list("add", anchor);
179 #if CPDEBUG < 0
180 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, anchor, elem)
181 #endif
183 static int
184 iseq_add_mark_object(rb_iseq_t *iseq, VALUE v)
186 if (!SPECIAL_CONST_P(v)) {
187 rb_ary_push(iseq->mark_ary, v);
189 return COMPILE_OK;
192 #define ruby_sourcefile RSTRING_PTR(iseq->filename)
194 static int
195 iseq_add_mark_object_compile_time(rb_iseq_t *iseq, VALUE v)
197 if (!SPECIAL_CONST_P(v)) {
198 rb_ary_push(iseq->compile_data->mark_ary, v);
200 return COMPILE_OK;
203 VALUE
204 iseq_compile(VALUE self, NODE *node)
206 DECL_ANCHOR(ret);
207 rb_iseq_t *iseq;
208 INIT_ANCHOR(ret);
209 GetISeqPtr(self, iseq);
211 if (node == 0) {
212 COMPILE(ret, "nil", node);
213 iseq_set_local_table(iseq, 0);
215 else if (nd_type(node) == NODE_SCOPE) {
216 /* iseq type of top, method, class, block */
217 iseq_set_local_table(iseq, node->nd_tbl);
218 iseq_set_arguments(iseq, ret, node->nd_args);
220 switch (iseq->type) {
221 case ISEQ_TYPE_BLOCK: {
222 LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
223 LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
225 ADD_LABEL(ret, start);
226 COMPILE(ret, "block body", node->nd_body);
227 ADD_LABEL(ret, end);
229 /* wide range catch handler must put at last */
230 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
231 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
232 break;
234 case ISEQ_TYPE_CLASS: {
235 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CLASS);
236 COMPILE(ret, "scoped node", node->nd_body);
237 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
238 break;
240 case ISEQ_TYPE_METHOD: {
241 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CALL);
242 COMPILE(ret, "scoped node", node->nd_body);
243 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
244 break;
246 default: {
247 COMPILE(ret, "scoped node", node->nd_body);
248 break;
252 else {
253 switch (iseq->type) {
254 case ISEQ_TYPE_METHOD:
255 case ISEQ_TYPE_CLASS:
256 case ISEQ_TYPE_BLOCK:
257 case ISEQ_TYPE_EVAL:
258 case ISEQ_TYPE_TOP:
259 rb_compile_error(ERROR_ARGS "compile/should not be reached: %s:%d",
260 __FILE__, __LINE__);
261 break;
262 case ISEQ_TYPE_RESCUE:
263 iseq_set_exception_local_table(iseq);
264 COMPILE(ret, "rescue", node);
265 break;
266 case ISEQ_TYPE_ENSURE:
267 iseq_set_exception_local_table(iseq);
268 COMPILE_POPED(ret, "ensure", node);
269 break;
270 case ISEQ_TYPE_DEFINED_GUARD:
271 iseq_set_local_table(iseq, 0);
272 COMPILE(ret, "defined guard", node);
273 break;
274 default:
275 rb_bug("unknown scope");
279 if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) {
280 ADD_INSN2(ret, 0, getdynamic, INT2FIX(2), INT2FIX(0));
281 ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
283 else {
284 ADD_INSN(ret, iseq->compile_data->last_line, leave);
287 return iseq_setup(iseq, ret);
291 iseq_translate_threaded_code(rb_iseq_t *iseq)
293 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
294 extern const void **vm_get_insns_address_table(void);
295 #if OPT_DIRECT_THREADED_CODE
296 const void * const *table = vm_get_insns_address_table();
297 #else
298 const void * const *table = vm_get_insns_address_table();
299 #endif
300 int i;
302 iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size);
303 MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size);
305 for (i = 0; i < iseq->iseq_size; /* */ ) {
306 int insn = iseq->iseq_encoded[i];
307 int len = insn_len(insn);
308 iseq->iseq_encoded[i] = (VALUE)table[insn];
309 i += len;
311 #else
312 iseq->iseq_encoded = iseq->iseq;
313 #endif
314 return COMPILE_OK;
317 /*********************************************/
318 /* definition of data structure for compiler */
319 /*********************************************/
321 static void *
322 compile_data_alloc(rb_iseq_t *iseq, size_t size)
324 void *ptr = 0;
325 struct iseq_compile_data_storage *storage =
326 iseq->compile_data->storage_current;
328 if (storage->pos + size > storage->size) {
329 unsigned long alloc_size = storage->size * 2;
331 retry:
332 if (alloc_size < size) {
333 alloc_size *= 2;
334 goto retry;
336 storage->next = (void *)ALLOC_N(char, alloc_size +
337 sizeof(struct
338 iseq_compile_data_storage));
339 storage = iseq->compile_data->storage_current = storage->next;
340 storage->next = 0;
341 storage->pos = 0;
342 storage->size = alloc_size;
343 storage->buff = (char *)(&storage->buff + 1);
346 ptr = (void *)&storage->buff[storage->pos];
347 storage->pos += size;
348 return ptr;
351 static INSN *
352 compile_data_alloc_insn(rb_iseq_t *iseq)
354 return (INSN *)compile_data_alloc(iseq, sizeof(INSN));
357 static LABEL *
358 compile_data_alloc_label(rb_iseq_t *iseq)
360 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
363 static ADJUST *
364 compile_data_alloc_adjust(rb_iseq_t *iseq)
366 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
370 * elem1, elemX => elem1, elem2, elemX
372 static void
373 INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
375 elem2->next = elem1->next;
376 elem2->prev = elem1;
377 elem1->next = elem2;
378 if (elem2->next) {
379 elem2->next->prev = elem2;
383 #if 0 /* unused */
385 * elemX, elem1 => elemX, elem2, elem1
387 static void
388 INSERT_ELEM_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
390 elem2->prev = elem1->prev;
391 elem2->next = elem1;
392 elem1->prev = elem2;
393 if (elem2->prev) {
394 elem2->prev->next = elem2;
397 #endif
400 * elemX, elem1, elemY => elemX, elem2, elemY
402 static void
403 REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
405 elem2->prev = elem1->prev;
406 elem2->next = elem1->next;
407 if (elem1->prev) {
408 elem1->prev->next = elem2;
410 if (elem1->next) {
411 elem1->next->prev = elem2;
415 static void
416 REMOVE_ELEM(LINK_ELEMENT *elem)
418 elem->prev->next = elem->next;
419 if (elem->next) {
420 elem->next->prev = elem->prev;
424 static LINK_ELEMENT *
425 FIRST_ELEMENT(LINK_ANCHOR *anchor)
427 return anchor->anchor.next;
430 #if 0 /* unused */
431 static LINK_ELEMENT *
432 LAST_ELEMENT(LINK_ANCHOR *anchor)
434 return anchor->last;
436 #endif
438 static LINK_ELEMENT *
439 POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
441 LINK_ELEMENT *elem = anchor->last;
442 anchor->last = anchor->last->prev;
443 anchor->last->next = 0;
444 verify_list("pop", anchor);
445 return elem;
447 #if CPDEBUG < 0
448 #define POP_ELEMENT(anchor) POP_ELEMENT(iseq, anchor)
449 #endif
451 #if 0 /* unused */
452 static LINK_ELEMENT *
453 SHIFT_ELEMENT(LINK_ANCHOR *anchor)
455 LINK_ELEMENT *elem = anchor->anchor.next;
456 if (elem) {
457 anchor->anchor.next = elem->next;
459 return elem;
461 #endif
463 #if 0 /* unused */
464 static int
465 LIST_SIZE(LINK_ANCHOR *anchor)
467 LINK_ELEMENT *elem = anchor->anchor.next;
468 int size = 0;
469 while (elem) {
470 size += 1;
471 elem = elem->next;
473 return size;
475 #endif
477 static int
478 LIST_SIZE_ZERO(LINK_ANCHOR *anchor)
480 if (anchor->anchor.next == 0) {
481 return 1;
483 else {
484 return 0;
489 * anc1: e1, e2, e3
490 * anc2: e4, e5
491 *#=>
492 * anc1: e1, e2, e3, e4, e5
493 * anc2: e4, e5 (broken)
495 static void
496 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
498 if (anc2->anchor.next) {
499 anc1->last->next = anc2->anchor.next;
500 anc2->anchor.next->prev = anc1->last;
501 anc1->last = anc2->last;
503 verify_list("append", anc1);
505 #if CPDEBUG < 0
506 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, anc1, anc2)
507 #endif
510 * anc1: e1, e2, e3
511 * anc2: e4, e5
512 *#=>
513 * anc1: e4, e5, e1, e2, e3
514 * anc2: e4, e5 (broken)
516 static void
517 INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
519 if (anc2->anchor.next) {
520 LINK_ELEMENT *first = anc1->anchor.next;
521 anc1->anchor.next = anc2->anchor.next;
522 anc1->anchor.next->prev = &anc1->anchor;
523 anc2->last->next = first;
524 if (first) {
525 first->prev = anc2->last;
527 else {
528 anc1->last = anc2->last;
532 verify_list("append", anc1);
534 #if CPDEBUG < 0
535 #define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, anc1, anc2)
536 #endif
538 #if 0 /* unused */
540 * anc1: e1, e2, e3
541 * anc2: e4, e5
542 *#=>
543 * anc1: e4, e5
544 * anc2: e1, e2, e3
546 static void
547 SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
549 LINK_ANCHOR tmp = *anc2;
551 /* it has bug */
552 *anc2 = *anc1;
553 *anc1 = tmp;
555 verify_list("swap1", anc1);
556 verify_list("swap2", anc2);
558 #if CPDEBUG < 0
559 #define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, anc1, anc2)
560 #endif
562 static LINK_ANCHOR *
563 REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc)
565 LINK_ELEMENT *first, *last, *elem, *e;
566 first = &anc->anchor;
567 elem = first->next;
568 last = anc->last;
570 if (elem != 0) {
571 anc->anchor.next = last;
572 anc->last = elem;
574 else {
575 /* null list */
576 return anc;
578 while (elem) {
579 e = elem->next;
580 elem->next = elem->prev;
581 elem->prev = e;
582 elem = e;
585 first->next = last;
586 last->prev = first;
587 anc->last->next = 0;
589 verify_list("reverse", anc);
590 return anc;
592 #if CPDEBUG < 0
593 #define REVERSE_LIST(anc) REVERSE_LIST(iseq, anc)
594 #endif
595 #endif
597 #if CPDEBUG && 0
598 static void
599 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
601 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
602 printf("----\n");
603 printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
604 anchor->anchor.next, anchor->last);
605 while (list) {
606 printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
607 list->prev, FIX2INT(list->type));
608 list = list->next;
610 printf("----\n");
612 dump_disasm_list(anchor->anchor.next);
613 verify_list("debug list", anchor);
615 #if CPDEBUG < 0
616 #define debug_list(anc) debug_list(iseq, anc)
617 #endif
618 #endif
620 static LABEL *
621 new_label_body(rb_iseq_t *iseq, int line)
623 LABEL *labelobj = compile_data_alloc_label(iseq);
625 labelobj->link.type = ISEQ_ELEMENT_LABEL;
626 labelobj->link.next = 0;
628 labelobj->label_no = iseq->compile_data->label_no++;
629 labelobj->sc_state = 0;
630 labelobj->sp = -1;
631 return labelobj;
634 static ADJUST *
635 new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
637 ADJUST *adjust = compile_data_alloc_adjust(iseq);
638 adjust->link.type = ISEQ_ELEMENT_ADJUST;
639 adjust->link.next = 0;
640 adjust->label = label;
641 adjust->line_no = line;
642 return adjust;
645 static INSN *
646 new_insn_core(rb_iseq_t *iseq, int line_no,
647 int insn_id, int argc, VALUE *argv)
649 INSN *iobj = compile_data_alloc_insn(iseq);
651 iobj->link.type = ISEQ_ELEMENT_INSN;
652 iobj->link.next = 0;
653 iobj->insn_id = insn_id;
654 iobj->line_no = line_no;
655 iobj->operands = argv;
656 iobj->operand_size = argc;
657 iobj->sc_state = 0;
658 return iobj;
661 static INSN *
662 new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...)
664 VALUE *operands = 0;
665 va_list argv;
666 if (argc > 0) {
667 int i;
668 va_init_list(argv, argc);
669 operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
670 for (i = 0; i < argc; i++) {
671 VALUE v = va_arg(argv, VALUE);
672 operands[i] = v;
674 va_end(argv);
676 return new_insn_core(iseq, line_no, insn_id, argc, operands);
679 static INSN *
680 new_insn_send(rb_iseq_t *iseq, int line_no,
681 VALUE id, VALUE argc, VALUE block, VALUE flag)
683 INSN *iobj = 0;
684 VALUE *operands =
685 (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 5);
686 operands[0] = id;
687 operands[1] = argc;
688 operands[2] = block;
689 operands[3] = flag;
690 operands[4] = 0;
691 iobj = new_insn_core(iseq, line_no, BIN(send), 5, operands);
692 return iobj;
695 static VALUE
696 new_child_iseq(rb_iseq_t *iseq, NODE *node,
697 VALUE name, VALUE parent, VALUE type)
699 VALUE ret;
701 debugs("[new_child_iseq]> ---------------------------------------\n");
702 ret = rb_iseq_new_with_opt(node, name, iseq_filename(iseq->self),
703 parent, type, iseq->compile_data->option);
704 debugs("[new_child_iseq]< ---------------------------------------\n");
705 iseq_add_mark_object(iseq, ret);
706 return ret;
709 static int
710 iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
712 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
714 if (compile_debug > 5)
715 dump_disasm_list(FIRST_ELEMENT(anchor));
717 debugs("[compile step 3.1 (iseq_optimize)]\n");
718 iseq_optimize(iseq, anchor);
720 if (compile_debug > 5)
721 dump_disasm_list(FIRST_ELEMENT(anchor));
723 if (iseq->compile_data->option->instructions_unification) {
724 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
725 iseq_insns_unification(iseq, anchor);
726 if (compile_debug > 5)
727 dump_disasm_list(FIRST_ELEMENT(anchor));
730 if (iseq->compile_data->option->stack_caching) {
731 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
732 iseq_set_sequence_stackcaching(iseq, anchor);
733 if (compile_debug > 5)
734 dump_disasm_list(FIRST_ELEMENT(anchor));
737 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
738 iseq_set_sequence(iseq, anchor);
739 if (compile_debug > 5)
740 dump_disasm_list(FIRST_ELEMENT(anchor));
742 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
743 iseq_set_exception_table(iseq);
745 debugs("[compile step 4.3 (set_optargs_table)] \n");
746 iseq_set_optargs_table(iseq);
748 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
749 iseq_translate_threaded_code(iseq);
751 if (compile_debug > 1) {
752 VALUE str = ruby_iseq_disasm(iseq->self);
753 printf("%s\n", StringValueCStr(str));
754 fflush(stdout);
756 debugs("[compile step: finish]\n");
758 return 0;
761 static int
762 iseq_set_exception_local_table(rb_iseq_t *iseq)
764 ID id_dollar_bang;
766 CONST_ID(id_dollar_bang, "#$!");
767 iseq->local_table = (ID *)ALLOC_N(ID *, 1);
768 iseq->local_table_size = 1;
769 iseq->local_size = iseq->local_table_size + 1;
770 iseq->local_table[0] = id_dollar_bang;
771 return COMPILE_OK;
774 static int
775 get_dyna_var_idx_at_raw(rb_iseq_t *iseq, ID id)
777 int i;
779 for (i = 0; i < iseq->local_table_size; i++) {
780 if (iseq->local_table[i] == id) {
781 return i;
784 return -1;
787 static int
788 get_local_var_idx(rb_iseq_t *iseq, ID id)
790 int idx = get_dyna_var_idx_at_raw(iseq->local_iseq, id);
792 if (idx < 0) {
793 rb_bug("get_local_var_idx: %d", idx);
796 return idx;
799 static int
800 get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls)
802 int lv = 0, idx = -1;
804 while (iseq) {
805 idx = get_dyna_var_idx_at_raw(iseq, id);
806 if (idx >= 0) {
807 break;
809 iseq = iseq->parent_iseq;
810 lv++;
813 if (idx < 0) {
814 rb_bug("get_dyna_var_idx: -1");
817 *level = lv;
818 *ls = iseq->local_size;
819 return idx;
822 static int
823 iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
825 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
827 if (node_args) {
828 NODE *node_aux = node_args->nd_next;
829 NODE *node_opt = node_args->nd_opt;
830 ID rest_id = 0;
831 int last_comma = 0;
832 ID block_id = 0;
833 NODE *node_init = 0;
835 if (nd_type(node_args) != NODE_ARGS) {
836 rb_bug("iseq_set_arguments: NODE_ARGS is expected, but %s",
837 ruby_node_name(nd_type(node_args)));
841 * new argument infromation:
842 * NODE_ARGS [m: int, o: NODE_OPT_ARG, ->]
843 * NODE_ARGS_AUX [r: ID, b: ID, ->]
844 * NODE_ARGS_AUX [Pst: id, Plen: int, init: NODE*]
845 * optarg information:
846 * NODE_OPT_ARGS [idx, expr, next ->]
847 * init arg:
848 * NODE_AND(m_init, p_init)
849 * if "r" is 1, it's means "{|x,|}" type block parameter.
852 iseq->argc = node_args->nd_frml;
853 debugs(" - argc: %d\n", iseq->argc);
855 if (node_aux) {
856 rest_id = node_aux->nd_rest;
857 if (rest_id == 1) {
858 last_comma = 1;
859 rest_id = 0;
861 block_id = (ID)node_aux->nd_body;
862 node_aux = node_aux->nd_next;
864 if (node_aux) {
865 ID post_start_id = node_aux->nd_pid;
866 iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, post_start_id);
867 iseq->arg_post_len = node_aux->nd_plen;
868 node_init = node_aux->nd_next;
872 if (node_opt) {
873 NODE *node = node_opt;
874 LABEL *label;
875 VALUE labels = rb_ary_new();
876 int i = 0, j;
878 while (node) {
879 label = NEW_LABEL(nd_line(node));
880 rb_ary_push(labels, (VALUE)label | 1);
881 ADD_LABEL(optargs, label);
882 COMPILE_POPED(optargs, "optarg", node->nd_body);
883 node = node->nd_next;
884 i += 1;
887 /* last label */
888 label = NEW_LABEL(nd_line(node_args));
889 rb_ary_push(labels, (VALUE)label | 1);
890 ADD_LABEL(optargs, label);
891 i += 1;
893 iseq->arg_opts = i;
894 iseq->arg_opt_table = ALLOC_N(VALUE, i);
895 MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i);
896 for (j = 0; j < i; j++) {
897 iseq->arg_opt_table[j] &= ~1;
900 else {
901 iseq->arg_opts = 0;
904 if (node_init) {
905 if (node_init->nd_1st) { /* m_init */
906 COMPILE_POPED(optargs, "init arguments (m)", node_init->nd_1st);
908 if (node_init->nd_2nd) { /* p_init */
909 COMPILE_POPED(optargs, "init arguments (p)", node_init->nd_2nd);
913 if (rest_id) {
914 iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id);
916 if (iseq->arg_rest == -1) {
917 rb_bug("arg_rest: -1");
920 if (iseq->arg_post_start == 0) {
921 iseq->arg_post_start = iseq->arg_rest + 1;
925 if (block_id) {
926 iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id);
929 if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 ||
930 iseq->arg_rest != -1 || iseq->arg_block != -1) {
931 iseq->arg_simple = 0;
933 /* set arg_size: size of arguments */
934 if (iseq->arg_block != -1) {
935 iseq->arg_size = iseq->arg_block + 1;
937 else if (iseq->arg_post_len) {
938 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
940 else if (iseq->arg_rest != -1) {
941 iseq->arg_size = iseq->arg_rest + 1;
943 else if (iseq->arg_opts) {
944 iseq->arg_size = iseq->argc + iseq->arg_opts - 1;
946 else {
947 iseq->arg_size = iseq->argc;
950 else {
951 iseq->arg_simple = 1;
952 iseq->arg_size = iseq->argc;
955 if (iseq->type == ISEQ_TYPE_BLOCK) {
956 if (iseq->arg_opts == 0 && iseq->arg_post_len == 0 && iseq->arg_rest == -1) {
957 if (iseq->argc == 1 && last_comma == 0) {
958 /* {|a|} */
959 iseq->arg_simple |= 0x02;
964 else {
965 iseq->arg_simple = 1;
968 return COMPILE_OK;
971 static int
972 iseq_set_local_table(rb_iseq_t *iseq, ID *tbl)
974 int size;
976 if (tbl) {
977 size = *tbl;
978 tbl++;
980 else {
981 size = 0;
984 if (size > 0) {
985 iseq->local_table = (ID *)ALLOC_N(ID *, size);
986 MEMCPY(iseq->local_table, tbl, ID *, size);
989 iseq->local_size = iseq->local_table_size = size;
990 iseq->local_size += 1;
992 if (lfp == dfp ) { // top, class, method
993 dfp[-1]: svar
994 else { // block
995 dfp[-1]: cref
999 debugs("iseq_set_local_table: %d, %d\n", iseq->local_size, iseq->local_table_size);
1000 return COMPILE_OK;
1004 ruby insn object array -> raw instruction sequence
1006 static int
1007 iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1009 LABEL *lobj;
1010 INSN *iobj;
1011 struct iseq_insn_info_entry *insn_info_table;
1012 LINK_ELEMENT *list;
1013 VALUE *generated_iseq;
1015 int k, pos, sp, stack_max = 0, line = 0;
1017 /* set label position */
1018 list = FIRST_ELEMENT(anchor);
1019 k = pos = 0;
1020 while (list) {
1021 switch (list->type) {
1022 case ISEQ_ELEMENT_INSN:
1024 iobj = (INSN *)list;
1025 line = iobj->line_no;
1026 pos += insn_data_length(iobj);
1027 k++;
1028 break;
1030 case ISEQ_ELEMENT_LABEL:
1032 lobj = (LABEL *)list;
1033 lobj->position = pos;
1034 lobj->set = Qtrue;
1035 break;
1037 case ISEQ_ELEMENT_NONE:
1039 /* ignore */
1040 break;
1042 case ISEQ_ELEMENT_ADJUST:
1044 ADJUST *adjust = (ADJUST *)list;
1045 if (adjust->line_no != -1) {
1046 pos += 2 /* insn + 1 operand */;
1047 k++;
1049 break;
1051 default:
1052 dump_disasm_list(FIRST_ELEMENT(anchor));
1053 dump_disasm_list(list);
1054 rb_compile_error(RSTRING_PTR(iseq->filename), line,
1055 "error: set_sequence");
1056 break;
1058 list = list->next;
1061 /* make instruction sequence */
1062 generated_iseq = ALLOC_N(VALUE, pos);
1063 insn_info_table = ALLOC_N(struct iseq_insn_info_entry, k);
1065 list = FIRST_ELEMENT(anchor);
1066 k = pos = sp = 0;
1068 while (list) {
1069 switch (list->type) {
1070 case ISEQ_ELEMENT_INSN:
1072 int j, len, insn;
1073 const char *types;
1074 VALUE *operands;
1076 iobj = (INSN *)list;
1078 /* update sp */
1079 sp = calc_sp_depth(sp, iobj);
1080 if (sp > stack_max) {
1081 stack_max = sp;
1084 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
1086 operands = iobj->operands;
1087 insn = iobj->insn_id;
1088 generated_iseq[pos] = insn;
1089 types = insn_op_types(insn);
1090 len = insn_len(insn);
1092 /* operand check */
1093 if (iobj->operand_size != len - 1) {
1094 dump_disasm_list(list);
1095 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1096 "operand size miss! (%d for %d)",
1097 iobj->operand_size, len - 1);
1098 return 0;
1101 for (j = 0; types[j]; j++) {
1102 char type = types[j];
1103 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
1104 switch (type) {
1105 case TS_OFFSET:
1107 /* label(destination position) */
1108 lobj = (LABEL *)operands[j];
1109 if (lobj->set != Qtrue) {
1110 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1111 "unknown label");
1113 if (lobj->sp == -1) {
1114 lobj->sp = sp;
1116 generated_iseq[pos + 1 + j] =
1117 lobj->position - (pos + len);
1118 break;
1120 case TS_CDHASH:
1123 * [obj, label, ...]
1125 int i;
1126 VALUE lits = operands[j];
1127 VALUE map = rb_hash_new();
1129 for (i=0; i < RARRAY_LEN(lits); i+=2) {
1130 VALUE obj = rb_ary_entry(lits, i);
1131 VALUE lv = rb_ary_entry(lits, i+1);
1132 lobj = (LABEL *)(lv & ~1);
1134 if (lobj->set != Qtrue) {
1135 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1136 "unknown label");
1138 rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len)));
1140 generated_iseq[pos + 1 + j] = map;
1141 iseq_add_mark_object(iseq, map);
1142 break;
1144 case TS_LINDEX:
1145 case TS_DINDEX:
1146 case TS_NUM: /* ulong */
1147 generated_iseq[pos + 1 + j] = FIX2INT(operands[j]);
1148 break;
1149 case TS_ISEQ: /* iseq */
1151 VALUE v = operands[j];
1152 rb_iseq_t *block = 0;
1153 if (v) {
1154 GetISeqPtr(v, block);
1156 generated_iseq[pos + 1 + j] = (VALUE)block;
1157 break;
1159 case TS_VALUE: /* VALUE */
1161 VALUE v = operands[j];
1162 generated_iseq[pos + 1 + j] = v;
1163 /* to mark ruby object */
1164 iseq_add_mark_object(iseq, v);
1165 break;
1167 case TS_IC: /* inline cache */
1169 VALUE v = (VALUE)NEW_INLINE_CACHE_ENTRY();
1170 generated_iseq[pos + 1 + j] = v;
1171 iseq_add_mark_object(iseq, v);
1172 break;
1174 case TS_ID: /* ID */
1175 generated_iseq[pos + 1 + j] = SYM2ID(operands[j]);
1176 break;
1177 case TS_GENTRY:
1179 struct global_entry *entry =
1180 (struct global_entry *)(operands[j] & (~1));
1181 generated_iseq[pos + 1 + j] = (VALUE)entry;
1183 break;
1184 default:
1185 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1186 "unknown operand type: %c", type);
1187 return 0;
1190 insn_info_table[k].line_no = iobj->line_no;
1191 insn_info_table[k].position = pos;
1192 insn_info_table[k].sp = sp;
1193 pos += len;
1194 k++;
1195 break;
1197 case ISEQ_ELEMENT_LABEL:
1199 lobj = (LABEL *)list;
1200 if (lobj->sp == -1) {
1201 lobj->sp = sp;
1203 else {
1204 sp = lobj->sp;
1206 break;
1208 case ISEQ_ELEMENT_ADJUST:
1210 ADJUST *adjust = (ADJUST *)list;
1211 int orig_sp = sp;
1213 if (adjust->label) {
1214 sp = adjust->label->sp;
1216 else {
1217 sp = 0;
1220 if (adjust->line_no != -1) {
1221 if (orig_sp - sp > 0) {
1222 insn_info_table[k].line_no = adjust->line_no;
1223 insn_info_table[k].position = pos;
1224 insn_info_table[k].sp = sp;
1225 k++;
1226 generated_iseq[pos++] = BIN(adjuststack);
1227 generated_iseq[pos++] = orig_sp - sp;
1229 else if (orig_sp - sp == 0) {
1230 /* jump to next insn */
1231 insn_info_table[k].line_no = adjust->line_no;
1232 insn_info_table[k].position = pos;
1233 insn_info_table[k].sp = sp;
1234 k++;
1235 generated_iseq[pos++] = BIN(jump);
1236 generated_iseq[pos++] = 0;
1238 else {
1239 rb_bug("iseq_set_sequence: adjust bug");
1242 break;
1244 default:
1245 /* ignore */
1246 break;
1248 list = list->next;
1251 #if 0 /* XXX */
1252 /* this check need dead code elimination */
1253 if (sp != 1) {
1254 rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
1256 #endif
1258 iseq->iseq = (void *)generated_iseq;
1259 iseq->iseq_size = pos;
1260 iseq->insn_info_table = insn_info_table;
1261 iseq->insn_info_size = k;
1262 iseq->stack_max = stack_max;
1264 return COMPILE_OK;
1267 static int
1268 label_get_position(LABEL *lobj)
1270 return lobj->position;
1273 static int
1274 label_get_sp(LABEL *lobj)
1276 return lobj->sp;
1279 static int
1280 iseq_set_exception_table(rb_iseq_t *iseq)
1282 VALUE *tptr, *ptr;
1283 int tlen, i;
1284 struct iseq_catch_table_entry *entry;
1286 tlen = RARRAY_LEN(iseq->compile_data->catch_table_ary);
1287 tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary);
1289 iseq->catch_table = tlen ? ALLOC_N(struct iseq_catch_table_entry, tlen) : 0;
1290 iseq->catch_table_size = tlen;
1292 for (i = 0; i < tlen; i++) {
1293 ptr = RARRAY_PTR(tptr[i]);
1294 entry = &iseq->catch_table[i];
1295 entry->type = ptr[0] & 0xffff;
1296 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
1297 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
1298 entry->iseq = ptr[3];
1300 /* register iseq as mark object */
1301 if (entry->iseq != 0) {
1302 iseq_add_mark_object(iseq, entry->iseq);
1305 /* stack depth */
1306 if (ptr[4]) {
1307 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
1308 entry->cont = label_get_position(lobj);
1309 entry->sp = label_get_sp(lobj);
1311 /* TODO: Dirty Hack! Fix me */
1312 if (entry->type == CATCH_TYPE_RESCUE ||
1313 entry->type == CATCH_TYPE_BREAK ||
1314 entry->type == CATCH_TYPE_NEXT) {
1315 entry->sp--;
1318 else {
1319 entry->cont = 0;
1323 iseq->compile_data->catch_table_ary = 0; /* free */
1324 return COMPILE_OK;
1328 * set optional argument table
1329 * def foo(a, b=expr1, c=expr2)
1330 * =>
1331 * b:
1332 * expr1
1333 * c:
1334 * expr2
1336 static int
1337 iseq_set_optargs_table(rb_iseq_t *iseq)
1339 int i;
1341 if (iseq->arg_opts != 0) {
1342 for (i = 0; i < iseq->arg_opts; i++) {
1343 iseq->arg_opt_table[i] =
1344 label_get_position((LABEL *)iseq->arg_opt_table[i]);
1347 return COMPILE_OK;
1350 static LINK_ELEMENT *
1351 get_destination_insn(INSN *iobj)
1353 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
1354 LINK_ELEMENT *list;
1356 list = lobj->link.next;
1357 while (list) {
1358 if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1359 break;
1361 list = list->next;
1363 return list;
1366 static LINK_ELEMENT *
1367 get_next_insn(INSN *iobj)
1369 LINK_ELEMENT *list = iobj->link.next;
1371 while (list) {
1372 if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1373 return list;
1375 list = list->next;
1377 return 0;
1380 static LINK_ELEMENT *
1381 get_prev_insn(INSN *iobj)
1383 LINK_ELEMENT *list = iobj->link.prev;
1385 while (list) {
1386 if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1387 return list;
1389 list = list->prev;
1391 return 0;
1394 static int
1395 iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
1397 INSN *iobj = (INSN *)list;
1398 again:
1399 if (iobj->insn_id == BIN(jump)) {
1400 INSN *niobj, *diobj, *piobj;
1402 * useless jump elimination:
1403 * jump LABEL1
1404 * ...
1405 * LABEL1:
1406 * jump LABEL2
1408 * => in this case, first jump instruction should jump tp
1409 * LABEL2 directly
1411 diobj = (INSN *)get_destination_insn(iobj);
1412 niobj = (INSN *)get_next_insn(iobj);
1414 if (diobj == niobj) {
1416 * jump LABEL
1417 * LABEL:
1418 * =>
1419 * LABEL:
1421 REMOVE_ELEM(&iobj->link);
1423 else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
1424 if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
1425 OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0);
1426 goto again;
1429 else if (diobj->insn_id == BIN(leave)) {
1431 * jump LABEL
1432 * ...
1433 * LABEL:
1434 * leave
1435 * =>
1436 * leave
1437 * ...
1438 * LABEL:
1439 * leave
1441 INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave),
1442 diobj->operand_size, diobj->operands);
1443 INSN *popiobj = new_insn_core(iseq, iobj->line_no,
1444 BIN(pop), 0, 0);
1445 /* replace */
1446 REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj);
1447 INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj);
1448 iobj = popiobj;
1451 * useless jump elimination (if/unless destination):
1452 * if L1
1453 * jump L2
1454 * L1:
1455 * ...
1456 * L2:
1458 * ==>
1459 * unless L2
1460 * L1:
1461 * ...
1462 * L2:
1464 else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 &&
1465 (piobj->insn_id == BIN(branchif) ||
1466 piobj->insn_id == BIN(branchunless))) {
1467 if (niobj == (INSN *)get_destination_insn(piobj)) {
1468 piobj->insn_id = (piobj->insn_id == BIN(branchif))
1469 ? BIN(branchunless) : BIN(branchif);
1470 OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0);
1471 REMOVE_ELEM(&iobj->link);
1476 if (iobj->insn_id == BIN(branchif) ||
1477 iobj->insn_id == BIN(branchunless)) {
1479 * if L1
1480 * ...
1481 * L1:
1482 * jump L2
1483 * =>
1484 * if L2
1486 INSN *nobj = (INSN *)get_destination_insn(iobj);
1487 if (nobj->insn_id == BIN(jump)) {
1488 OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
1492 if (do_tailcallopt && iobj->insn_id == BIN(leave)) {
1494 * send ...
1495 * leave
1496 * =>
1497 * send ..., ... | VM_CALL_TAILCALL_BIT, ...
1498 * leave # unreachable
1500 INSN *piobj = (INSN *)get_prev_insn((INSN *)list);
1502 if (piobj->insn_id == BIN(send) &&
1503 piobj->operands[2] == 0 /* block */
1505 piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT);
1508 return COMPILE_OK;
1511 static int
1512 insn_set_specialized_instruction(INSN *iobj, int insn_id)
1514 iobj->insn_id = insn_id;
1515 iobj->operand_size = 0;
1516 return COMPILE_OK;
1519 static int
1520 insn_set_specialized_instruction_with_ic(INSN *iobj, int insn_id, int n)
1522 int i;
1523 iobj->insn_id = insn_id;
1524 iobj->operand_size = n;
1526 /* max of n is 4 */
1527 for (i=0; i<n; i++) {
1528 iobj->operands[i] = Qnil;
1531 return COMPILE_OK;
1535 static int
1536 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
1538 if (iobj->insn_id == BIN(send)) {
1539 ID mid = SYM2ID(OPERAND_AT(iobj, 0));
1540 int argc = FIX2INT(OPERAND_AT(iobj, 1));
1541 VALUE block = OPERAND_AT(iobj, 2);
1542 VALUE flag = OPERAND_AT(iobj, 3);
1544 /* TODO: should be more sophisticated search */
1545 if (block == 0 && flag == INT2FIX(0)) {
1546 if (argc == 0) {
1547 if (mid == idLength) {
1548 insn_set_specialized_instruction(iobj, BIN(opt_length));
1550 else if (mid == idSucc) {
1551 insn_set_specialized_instruction(iobj, BIN(opt_succ));
1553 else if (mid == idNot) {
1554 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_not), 1);
1557 else if (argc == 1) {
1558 if (0) {
1560 else if (mid == idPLUS) {
1561 insn_set_specialized_instruction(iobj, BIN(opt_plus));
1563 else if (mid == idMINUS) {
1564 insn_set_specialized_instruction(iobj, BIN(opt_minus));
1566 else if (mid == idMULT) {
1567 insn_set_specialized_instruction(iobj, BIN(opt_mult));
1569 else if (mid == idDIV) {
1570 insn_set_specialized_instruction(iobj, BIN(opt_div));
1572 else if (mid == idMOD) {
1573 insn_set_specialized_instruction(iobj, BIN(opt_mod));
1575 else if (mid == idEq) {
1576 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_eq), 1);
1578 else if (mid == idNeq) {
1579 insn_set_specialized_instruction_with_ic(iobj, BIN(opt_neq), 2);
1581 else if (mid == idLT) {
1582 insn_set_specialized_instruction(iobj, BIN(opt_lt));
1584 else if (mid == idLE) {
1585 insn_set_specialized_instruction(iobj, BIN(opt_le));
1587 else if (mid == idGT) {
1588 insn_set_specialized_instruction(iobj, BIN(opt_gt));
1590 else if (mid == idGE) {
1591 insn_set_specialized_instruction(iobj, BIN(opt_ge));
1593 else if (mid == idLTLT) {
1594 insn_set_specialized_instruction(iobj, BIN(opt_ltlt));
1596 else if (mid == idAREF) {
1597 insn_set_specialized_instruction(iobj, BIN(opt_aref));
1602 if (argc > 0) {
1603 if (mid == idSend || mid == id__send__ ) {
1604 OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT);
1608 return COMPILE_OK;
1611 static int
1612 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1614 LINK_ELEMENT *list;
1615 const int do_peepholeopt = iseq->compile_data->option->peephole_optimization;
1616 const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization;
1617 const int do_si = iseq->compile_data->option->specialized_instruction;
1618 const int do_ou = iseq->compile_data->option->operands_unification;
1619 list = FIRST_ELEMENT(anchor);
1621 while (list) {
1622 if (list->type == ISEQ_ELEMENT_INSN) {
1623 if (do_peepholeopt) {
1624 iseq_peephole_optimize(iseq, list, do_tailcallopt);
1626 if (do_si) {
1627 iseq_specialized_instruction(iseq, (INSN *)list);
1629 if (do_ou) {
1630 insn_operands_unification((INSN *)list);
1633 list = list->next;
1635 return COMPILE_OK;
1638 #if OPT_INSTRUCTIONS_UNIFICATION
1639 static INSN *
1640 new_unified_insn(rb_iseq_t *iseq,
1641 int insn_id, int size, LINK_ELEMENT *seq_list)
1643 INSN *iobj = 0;
1644 LINK_ELEMENT *list = seq_list;
1645 int i, argc = 0;
1646 VALUE *operands = 0, *ptr = 0;
1649 /* count argc */
1650 for (i = 0; i < size; i++) {
1651 iobj = (INSN *)list;
1652 argc += iobj->operand_size;
1653 list = list->next;
1656 if (argc > 0) {
1657 ptr = operands =
1658 (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
1661 /* copy operands */
1662 list = seq_list;
1663 for (i = 0; i < size; i++) {
1664 iobj = (INSN *)list;
1665 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
1666 ptr += iobj->operand_size;
1667 list = list->next;
1670 return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands);
1672 #endif
1675 * This scheme can get more performance if do this optimize with
1676 * label address resolving.
1677 * It's future work (if compile time was bottle neck).
1679 static int
1680 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1682 #if OPT_INSTRUCTIONS_UNIFICATION
1683 LINK_ELEMENT *list;
1684 INSN *iobj, *niobj;
1685 int id, j, k;
1687 list = FIRST_ELEMENT(anchor);
1688 while (list) {
1689 if (list->type == ISEQ_ELEMENT_INSN) {
1690 iobj = (INSN *)list;
1691 id = iobj->insn_id;
1692 if (unified_insns_data[id] != 0) {
1693 const int *const *entry = unified_insns_data[id];
1694 for (j = 1; j < (int)entry[0]; j++) {
1695 const int *unified = entry[j];
1696 LINK_ELEMENT *li = list->next;
1697 for (k = 2; k < unified[1]; k++) {
1698 if (li->type != ISEQ_ELEMENT_INSN ||
1699 ((INSN *)li)->insn_id != unified[k]) {
1700 goto miss;
1702 li = li->next;
1704 /* matched */
1705 niobj =
1706 new_unified_insn(iseq, unified[0], unified[1] - 1,
1707 list);
1709 /* insert to list */
1710 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
1711 niobj->link.next = li;
1712 if (li) {
1713 li->prev = (LINK_ELEMENT *)niobj;
1716 list->prev->next = (LINK_ELEMENT *)niobj;
1717 list = (LINK_ELEMENT *)niobj;
1718 break;
1719 miss:;
1723 list = list->next;
1725 #endif
1726 return COMPILE_OK;
1729 #if OPT_STACK_CACHING
1731 #define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
1732 #define SC_NEXT(insn) sc_insn_next[insn]
1734 #include "opt_sc.inc"
1736 static int
1737 insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state)
1739 int nstate;
1740 int insn_id;
1742 insn_id = iobj->insn_id;
1743 iobj->insn_id = SC_INSN(insn_id, state);
1744 nstate = SC_NEXT(iobj->insn_id);
1746 if (insn_id == BIN(jump) ||
1747 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
1748 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
1750 if (lobj->sc_state != 0) {
1751 if (lobj->sc_state != nstate) {
1752 dump_disasm_list((LINK_ELEMENT *)iobj);
1753 dump_disasm_list((LINK_ELEMENT *)lobj);
1754 printf("\n-- %d, %d\n", lobj->sc_state, nstate);
1755 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->lineno,
1756 "insn_set_sc_state error\n");
1757 return 0;
1760 else {
1761 lobj->sc_state = nstate;
1763 if (insn_id == BIN(jump)) {
1764 nstate = SCS_XX;
1767 else if (insn_id == BIN(leave)) {
1768 nstate = SCS_XX;
1771 return nstate;
1774 static int
1775 label_set_sc_state(LABEL *lobj, int state)
1777 if (lobj->sc_state != 0) {
1778 if (lobj->sc_state != state) {
1779 state = lobj->sc_state;
1782 else {
1783 lobj->sc_state = state;
1786 return state;
1790 #endif
1792 static int
1793 iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1795 #if OPT_STACK_CACHING
1796 LINK_ELEMENT *list;
1797 int state, insn_id;
1799 /* initialize */
1800 state = SCS_XX;
1801 list = FIRST_ELEMENT(anchor);
1802 /* dump_disasm_list(list); */
1804 /* for each list element */
1805 while (list) {
1806 redo_point:
1807 switch (list->type) {
1808 case ISEQ_ELEMENT_INSN:
1810 INSN *iobj = (INSN *)list;
1811 insn_id = iobj->insn_id;
1813 /* dump_disasm_list(list); */
1815 switch (insn_id) {
1816 case BIN(nop):
1818 /* exception merge point */
1819 if (state != SCS_AX) {
1820 INSN *rpobj =
1821 new_insn_body(iseq, 0, BIN(reput), 0);
1823 /* replace this insn */
1824 REPLACE_ELEM(list, (LINK_ELEMENT *)rpobj);
1825 list = (LINK_ELEMENT *)rpobj;
1826 goto redo_point;
1828 break;
1830 case BIN(swap):
1832 if (state == SCS_AB || state == SCS_BA) {
1833 state = (state == SCS_AB ? SCS_BA : SCS_AB);
1835 REMOVE_ELEM(list);
1836 list = list->next;
1837 goto redo_point;
1839 break;
1841 case BIN(pop):
1843 switch (state) {
1844 case SCS_AX:
1845 case SCS_BX:
1846 state = SCS_XX;
1847 break;
1848 case SCS_AB:
1849 state = SCS_AX;
1850 break;
1851 case SCS_BA:
1852 state = SCS_BX;
1853 break;
1854 case SCS_XX:
1855 goto normal_insn;
1856 default:
1857 rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
1858 "unreachable");
1860 /* remove useless pop */
1861 REMOVE_ELEM(list);
1862 list = list->next;
1863 goto redo_point;
1865 default:;
1866 /* none */
1867 } /* end of switch */
1868 normal_insn:
1869 state = insn_set_sc_state(iseq, iobj, state);
1870 break;
1872 case ISEQ_ELEMENT_LABEL:
1874 LABEL *lobj;
1875 lobj = (LABEL *)list;
1877 state = label_set_sc_state(lobj, state);
1879 default:
1880 break;
1882 list = list->next;
1884 #endif
1885 return COMPILE_OK;
1890 static int
1891 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int *cntp)
1893 NODE *list = node->nd_next;
1894 VALUE lit = node->nd_lit;
1895 int cnt = 1;
1897 debugp_param("nd_lit", lit);
1898 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
1900 while (list) {
1901 COMPILE(ret, "each string", list->nd_head);
1902 cnt++;
1903 list = list->nd_next;
1905 *cntp = cnt;
1907 return COMPILE_OK;
1910 static int
1911 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
1913 int cnt;
1914 compile_dstr_fragments(iseq, ret, node, &cnt);
1915 ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
1916 return COMPILE_OK;
1919 static int
1920 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
1922 int cnt;
1923 compile_dstr_fragments(iseq, ret, node, &cnt);
1924 ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
1925 return COMPILE_OK;
1928 static int
1929 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
1930 LABEL *then_label, LABEL *else_label)
1932 switch (nd_type(cond)) {
1933 case NODE_AND:
1935 LABEL *label = NEW_LABEL(nd_line(cond));
1936 compile_branch_condition(iseq, ret, cond->nd_1st, label,
1937 else_label);
1938 ADD_LABEL(ret, label);
1939 compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
1940 else_label);
1941 break;
1943 case NODE_OR:
1945 LABEL *label = NEW_LABEL(nd_line(cond));
1946 compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
1947 label);
1948 ADD_LABEL(ret, label);
1949 compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
1950 else_label);
1951 break;
1953 case NODE_LIT: /* NODE_LIT is always not true */
1954 case NODE_TRUE:
1955 case NODE_STR:
1956 /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
1957 ADD_INSNL(ret, nd_line(cond), jump, then_label);
1958 break;
1959 case NODE_FALSE:
1960 case NODE_NIL:
1961 /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
1962 ADD_INSNL(ret, nd_line(cond), jump, else_label);
1963 break;
1964 default:
1965 COMPILE(ret, "branch condition", cond);
1966 ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
1967 ADD_INSNL(ret, nd_line(cond), jump, then_label);
1968 break;
1970 return COMPILE_OK;
1973 static int
1974 compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
1975 VALUE opt_p, int poped)
1977 NODE *node = node_root;
1978 int len = node->nd_alen, line = nd_line(node), i=0;
1979 DECL_ANCHOR(anchor);
1981 INIT_ANCHOR(anchor);
1982 if (nd_type(node) != NODE_ZARRAY) {
1983 while (node) {
1984 if (nd_type(node) != NODE_ARRAY) {
1985 rb_bug("compile_array: This node is not NODE_ARRAY, but %s",
1986 ruby_node_name(nd_type(node)));
1989 i++;
1990 if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
1991 opt_p = Qfalse;
1993 COMPILE_(anchor, "array element", node->nd_head, poped);
1994 node = node->nd_next;
1998 if (len != i) {
1999 if (0) {
2000 rb_bug("node error: compile_array (%d: %d-%d)",
2001 (int)nd_line(node_root), len, i);
2003 len = i;
2006 if (opt_p == Qtrue) {
2007 if (!poped) {
2008 VALUE ary = rb_ary_new();
2009 node = node_root;
2010 while (node) {
2011 rb_ary_push(ary, node->nd_head->nd_lit);
2012 node = node->nd_next;
2015 iseq_add_mark_object_compile_time(iseq, ary);
2016 ADD_INSN1(ret, nd_line(node_root), duparray, ary);
2019 else {
2020 if (!poped) {
2021 ADD_INSN1(anchor, line, newarray, INT2FIX(len));
2023 APPEND_LIST(ret, anchor);
2025 return len;
2028 static VALUE
2029 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, VALUE opt_p)
2031 return compile_array_(iseq, ret, node_root, opt_p, 0);
2034 static VALUE
2035 case_when_optimizable_literal(NODE * node)
2037 switch (nd_type(node)) {
2038 case NODE_LIT: {
2039 VALUE v = node->nd_lit;
2040 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
2041 return v;
2043 break;
2045 case NODE_STR:
2046 return node->nd_lit;
2048 return Qfalse;
2051 static VALUE
2052 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literals)
2054 while (vals) {
2055 VALUE lit;
2056 NODE* val;
2058 val = vals->nd_head;
2060 if (special_literals &&
2061 (lit = case_when_optimizable_literal(val)) != Qfalse) {
2062 rb_ary_push(special_literals, lit);
2063 rb_ary_push(special_literals, (VALUE)(l1) | 1);
2065 else {
2066 special_literals = Qfalse;
2069 COMPILE(cond_seq, "when cond", val);
2070 ADD_INSN1(cond_seq, nd_line(val), topn, INT2FIX(1));
2071 ADD_SEND(cond_seq, nd_line(val), ID2SYM(idEqq), INT2FIX(1));
2072 ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
2073 vals = vals->nd_next;
2075 return special_literals;
2078 static int
2079 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
2081 switch (nd_type(node)) {
2082 case NODE_ATTRASGN: {
2083 INSN *iobj;
2084 VALUE dupidx;
2086 COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node);
2087 POP_ELEMENT(ret); /* pop pop insn */
2088 iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */
2090 dupidx = iobj->operands[1];
2091 dupidx = INT2FIX(FIX2INT(dupidx) + 1);
2092 iobj->operands[1] = dupidx;
2094 ADD_INSN1(ret, nd_line(node), topn, dupidx);
2095 ADD_ELEM(ret, (LINK_ELEMENT *)iobj);
2096 ADD_INSN(ret, nd_line(node), pop); /* result */
2097 ADD_INSN(ret, nd_line(node), pop); /* rhs */
2098 break;
2100 case NODE_MASGN: {
2101 DECL_ANCHOR(anchor);
2102 INIT_ANCHOR(anchor);
2103 COMPILE_POPED(anchor, "nest masgn lhs", node);
2104 REMOVE_ELEM(FIRST_ELEMENT(anchor));
2105 ADD_SEQ(ret, anchor);
2106 break;
2108 default: {
2109 DECL_ANCHOR(anchor);
2110 INIT_ANCHOR(anchor);
2111 COMPILE_POPED(anchor, "masgn lhs", node);
2112 REMOVE_ELEM(FIRST_ELEMENT(anchor));
2113 ADD_SEQ(ret, anchor);
2117 return COMPILE_OK;
2120 static void
2121 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn)
2123 if (lhsn) {
2124 compile_massign_opt_lhs(iseq, ret, lhsn->nd_next);
2125 compile_massign_lhs(iseq, ret, lhsn->nd_head);
2129 static int
2130 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2131 NODE *rhsn, NODE *orig_lhsn)
2133 VALUE mem[64];
2134 const int memsize = sizeof(mem) / sizeof(mem[0]);
2135 int memindex = 0;
2136 int llen = 0, rlen = 0;
2137 int i;
2138 NODE *lhsn = orig_lhsn;
2140 #define MEMORY(v) { \
2141 int i; \
2142 if (memindex == memsize) return 0; \
2143 for (i=0; i<memindex; i++) { \
2144 if (mem[i] == (v)) return 0; \
2146 mem[memindex++] = (v); \
2149 if (rhsn == 0 || nd_type(rhsn) != NODE_ARRAY) {
2150 return 0;
2153 while (lhsn) {
2154 NODE *ln = lhsn->nd_head;
2155 switch (nd_type(ln)) {
2156 case NODE_LASGN:
2157 MEMORY(ln->nd_vid);
2158 break;
2159 case NODE_DASGN:
2160 case NODE_DASGN_CURR:
2161 case NODE_IASGN:
2162 case NODE_IASGN2:
2163 case NODE_CVASGN:
2164 MEMORY(ln->nd_vid);
2165 break;
2166 default:
2167 return 0;
2169 lhsn = lhsn->nd_next;
2170 llen++;
2173 while (rhsn) {
2174 if (llen <= rlen) {
2175 COMPILE_POPED(ret, "masgn val (poped)", rhsn->nd_head);
2177 else {
2178 COMPILE(ret, "masgn val", rhsn->nd_head);
2180 rhsn = rhsn->nd_next;
2181 rlen++;
2184 if (llen > rlen) {
2185 for (i=0; i<llen-rlen; i++) {
2186 ADD_INSN(ret, nd_line(orig_lhsn), putnil);
2190 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
2191 return 1;
2194 static int
2195 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped)
2197 NODE *rhsn = node->nd_value;
2198 NODE *splatn = node->nd_args;
2199 NODE *lhsn = node->nd_head;
2200 int lhs_splat = (splatn && (VALUE)splatn != (VALUE)-1) ? 1 : 0;
2202 if (!poped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
2203 int llen = 0;
2204 DECL_ANCHOR(lhsseq);
2206 INIT_ANCHOR(lhsseq);
2208 while (lhsn) {
2209 compile_massign_lhs(iseq, lhsseq, lhsn->nd_head);
2210 llen += 1;
2211 lhsn = lhsn->nd_next;
2214 COMPILE(ret, "normal masgn rhs", rhsn);
2216 if (!poped) {
2217 ADD_INSN(ret, nd_line(node), dup);
2220 ADD_INSN2(ret, nd_line(node), expandarray,
2221 INT2FIX(llen), INT2FIX(lhs_splat));
2222 ADD_SEQ(ret, lhsseq);
2224 if (lhs_splat) {
2225 if (nd_type(splatn) == NODE_POSTARG) {
2226 /*a, b, *r, p1, p2 */
2227 NODE *postn = splatn->nd_2nd;
2228 NODE *restn = splatn->nd_1st;
2229 int num = postn->nd_alen;
2230 int flag = 0x02 | (((VALUE)restn == (VALUE)-1) ? 0x00 : 0x01);
2232 ADD_INSN2(ret, nd_line(splatn), expandarray,
2233 INT2FIX(num), INT2FIX(flag));
2235 if ((VALUE)restn != (VALUE)-1) {
2236 compile_massign_lhs(iseq, ret, restn);
2238 while (postn) {
2239 compile_massign_lhs(iseq, ret, postn->nd_head);
2240 postn = postn->nd_next;
2243 else {
2244 /* a, b, *r */
2245 compile_massign_lhs(iseq, ret, splatn);
2249 return COMPILE_OK;
2252 static int
2253 compile_colon2(rb_iseq_t *iseq, NODE * node,
2254 LINK_ANCHOR *pref, LINK_ANCHOR *body)
2256 switch (nd_type(node)) {
2257 case NODE_CONST:
2258 debugi("compile_colon2 - colon", node->nd_vid);
2259 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
2260 break;
2261 case NODE_COLON3:
2262 debugi("compile_colon2 - colon3", node->nd_mid);
2263 ADD_INSN(body, nd_line(node), pop);
2264 ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
2265 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2266 break;
2267 case NODE_COLON2:
2268 compile_colon2(iseq, node->nd_head, pref, body);
2269 debugi("compile_colon2 - colon2", node->nd_mid);
2270 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2271 break;
2272 default:
2273 COMPILE(pref, "const colon2 prefix", node);
2274 break;
2276 return COMPILE_OK;
2279 static VALUE
2280 compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
2282 if (nd_type(cpath) == NODE_COLON3) {
2283 /* toplevel class ::Foo */
2284 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
2285 return Qfalse;
2287 else if (cpath->nd_head) {
2288 /* Bar::Foo */
2289 COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
2290 return Qfalse;
2292 else {
2293 /* class at cbase Foo */
2294 ADD_INSN1(ret, nd_line(cpath), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
2295 return Qtrue;
2299 static int
2300 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2301 NODE *node, LABEL **lfinish, VALUE needstr)
2303 const char *estr = 0;
2304 enum node_type type;
2306 switch (type = nd_type(node)) {
2308 /* easy literals */
2309 case NODE_NIL:
2310 estr = "nil";
2311 break;
2312 case NODE_SELF:
2313 estr = "self";
2314 break;
2315 case NODE_TRUE:
2316 estr = "true";
2317 break;
2318 case NODE_FALSE:
2319 estr = "false";
2320 break;
2322 case NODE_ARRAY:{
2323 NODE *vals = node;
2325 do {
2326 defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
2328 if (!lfinish[1]) {
2329 lfinish[1] = NEW_LABEL(nd_line(node));
2331 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2332 } while ((vals = vals->nd_next) != NULL);
2334 case NODE_STR:
2335 case NODE_LIT:
2336 case NODE_ZARRAY:
2337 estr = "expression";
2338 break;
2340 /* variables */
2341 case NODE_LVAR:
2342 case NODE_DVAR:
2343 estr = "local-variable";
2344 break;
2346 case NODE_IVAR:
2347 ADD_INSN(ret, nd_line(node), putnil);
2348 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR),
2349 ID2SYM(node->nd_vid), needstr);
2350 return 1;
2352 case NODE_GVAR:
2353 ADD_INSN(ret, nd_line(node), putnil);
2354 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR),
2355 ((VALUE)node->nd_entry) | 1, needstr);
2356 return 1;
2358 case NODE_CVAR:
2359 ADD_INSN(ret, nd_line(node), putnil);
2360 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR),
2361 ID2SYM(node->nd_vid), needstr);
2362 return 1;
2364 case NODE_CONST:
2365 ADD_INSN(ret, nd_line(node), putnil);
2366 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2367 ID2SYM(node->nd_vid), needstr);
2368 return 1;
2369 case NODE_COLON2:
2370 if (!lfinish[1]) {
2371 lfinish[1] = NEW_LABEL(nd_line(node));
2373 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
2374 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2376 if (rb_is_const_id(node->nd_mid)) {
2377 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2378 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2379 ID2SYM(node->nd_mid), needstr);
2381 else {
2382 COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2383 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2384 ID2SYM(node->nd_mid), needstr);
2386 return 1;
2387 case NODE_COLON3:
2388 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
2389 ADD_INSN3(ret, nd_line(node), defined,
2390 INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
2391 return 1;
2393 /* method dispatch */
2394 case NODE_CALL:
2395 case NODE_VCALL:
2396 case NODE_FCALL:
2397 case NODE_ATTRASGN:{
2398 int self = Qtrue;
2400 switch (type) {
2401 case NODE_ATTRASGN:
2402 if (node->nd_recv == (NODE *)1) break;
2403 case NODE_CALL:
2404 self = Qfalse;
2405 break;
2406 default:
2407 /* through */;
2409 if (!lfinish[1]) {
2410 lfinish[1] = NEW_LABEL(nd_line(node));
2412 if (node->nd_args) {
2413 defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
2414 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2416 if (!self) {
2417 LABEL *lstart = NEW_LABEL(nd_line(node));
2418 LABEL *lend = NEW_LABEL(nd_line(node));
2419 VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
2420 rb_str_concat(rb_str_new2
2421 ("defined guard in "),
2422 iseq->name),
2423 ISEQ_TYPE_DEFINED_GUARD);
2425 defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
2426 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2428 ADD_LABEL(ret, lstart);
2429 COMPILE(ret, "defined/recv", node->nd_recv);
2430 ADD_LABEL(ret, lend);
2431 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
2432 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2433 ID2SYM(node->nd_mid), needstr);
2435 else {
2436 ADD_INSN(ret, nd_line(node), putself);
2437 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
2438 ID2SYM(node->nd_mid), needstr);
2440 return 1;
2443 case NODE_YIELD:
2444 ADD_INSN(ret, nd_line(node), putnil);
2445 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0,
2446 needstr);
2447 return 1;
2449 case NODE_BACK_REF:
2450 case NODE_NTH_REF:
2451 ADD_INSN(ret, nd_line(node), putnil);
2452 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
2453 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
2454 needstr);
2455 return 1;
2457 case NODE_SUPER:
2458 case NODE_ZSUPER:
2459 ADD_INSN(ret, nd_line(node), putnil);
2460 ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
2461 needstr);
2462 return 1;
2464 case NODE_OP_ASGN1:
2465 case NODE_OP_ASGN2:
2466 case NODE_OP_ASGN_OR:
2467 case NODE_OP_ASGN_AND:
2468 case NODE_MASGN:
2469 case NODE_LASGN:
2470 case NODE_DASGN:
2471 case NODE_DASGN_CURR:
2472 case NODE_GASGN:
2473 case NODE_IASGN:
2474 case NODE_CDECL:
2475 case NODE_CVDECL:
2476 case NODE_CVASGN:
2477 estr = "assignment";
2478 break;
2480 default:{
2481 LABEL *lstart = NEW_LABEL(nd_line(node));
2482 LABEL *lend = NEW_LABEL(nd_line(node));
2483 VALUE ensure = NEW_CHILD_ISEQVAL(NEW_NIL(),
2484 rb_str_concat(rb_str_new2
2485 ("defined guard in "),
2486 iseq->name),
2487 ISEQ_TYPE_DEFINED_GUARD);
2489 ADD_LABEL(ret, lstart);
2490 COMPILE(ret, "defined expr (others)", node);
2491 if (!lfinish[1]) {
2492 lfinish[1] = NEW_LABEL(nd_line(node));
2494 ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2495 if (needstr) {
2496 ADD_INSN1(ret, nd_line(node), putstring, rb_str_new2("expression"));
2498 else {
2499 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2501 ADD_LABEL(ret, lend);
2503 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, ensure, lfinish[1]);
2504 return 1;
2505 } /* end of default */
2508 if (estr != 0) {
2509 if (needstr != Qfalse) {
2510 VALUE str = rb_str_new2(estr);
2511 ADD_INSN1(ret, nd_line(node), putstring, str);
2512 iseq_add_mark_object_compile_time(iseq, str);
2514 else {
2515 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2517 return 1;
2519 return 0;
2522 #define BUFSIZE 0x100
2524 static VALUE
2525 make_name_for_block(rb_iseq_t *iseq)
2527 if (iseq->parent_iseq == 0) {
2528 return rb_sprintf("block in %s", RSTRING_PTR(iseq->name));
2530 else {
2531 int level = 1;
2532 rb_iseq_t *ip = iseq;
2533 while (ip->local_iseq != ip) {
2534 ip = ip->parent_iseq;
2535 level++;
2537 return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->name));
2541 static void
2542 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
2543 LABEL *lstart, LABEL *lend)
2545 struct ensure_range *ne =
2546 compile_data_alloc(iseq, sizeof(struct ensure_range));
2548 while (erange->next != 0) {
2549 erange = erange->next;
2551 ne->next = 0;
2552 ne->begin = lend;
2553 ne->end = erange->end;
2554 erange->end = lstart;
2556 erange->next = ne;
2559 static void
2560 add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq)
2562 struct iseq_compile_data_ensure_node_stack *enlp =
2563 iseq->compile_data->ensure_node_stack;
2564 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
2565 DECL_ANCHOR(ensure);
2567 INIT_ANCHOR(ensure);
2568 while (enlp) {
2569 DECL_ANCHOR(ensure_part);
2570 LABEL *lstart = NEW_LABEL(0);
2571 LABEL *lend = NEW_LABEL(0);
2573 INIT_ANCHOR(ensure_part);
2574 add_ensure_range(iseq, enlp->erange, lstart, lend);
2576 iseq->compile_data->ensure_node_stack = enlp->prev;
2577 ADD_LABEL(ensure_part, lstart);
2578 COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
2579 ADD_LABEL(ensure_part, lend);
2581 ADD_SEQ(ensure, ensure_part);
2582 enlp = enlp->prev;
2584 iseq->compile_data->ensure_node_stack = prev_enlp;
2585 ADD_SEQ(ret, ensure);
2588 static VALUE
2589 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned long *flag)
2591 VALUE argc = INT2FIX(0);
2592 int nsplat = 0;
2593 DECL_ANCHOR(arg_block);
2594 DECL_ANCHOR(args_splat);
2596 INIT_ANCHOR(arg_block);
2597 INIT_ANCHOR(args_splat);
2598 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
2599 COMPILE(arg_block, "block", argn->nd_body);
2600 *flag |= VM_CALL_ARGS_BLOCKARG_BIT;
2601 argn = argn->nd_head;
2604 setup_argn:
2605 if (argn) {
2606 switch (nd_type(argn)) {
2607 case NODE_SPLAT: {
2608 COMPILE(args, "args (splat)", argn->nd_head);
2609 argc = INT2FIX(1);
2610 nsplat++;
2611 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2612 break;
2614 case NODE_ARGSCAT:
2615 case NODE_ARGSPUSH: {
2616 int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
2617 DECL_ANCHOR(tmp);
2619 INIT_ANCHOR(tmp);
2620 COMPILE(tmp, "args (cat: splat)", argn->nd_body);
2621 if (next_is_array && nsplat == 0) {
2622 /* none */
2624 else {
2625 if (nd_type(argn) == NODE_ARGSCAT) {
2626 ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
2628 else {
2629 ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1));
2632 INSERT_LIST(args_splat, tmp);
2633 nsplat++;
2634 *flag |= VM_CALL_ARGS_SPLAT_BIT;
2636 if (next_is_array) {
2637 argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) + 1);
2638 POP_ELEMENT(args);
2640 else {
2641 argn = argn->nd_head;
2642 goto setup_argn;
2644 break;
2646 case NODE_ARRAY: {
2647 argc = INT2FIX(compile_array(iseq, args, argn, Qfalse));
2648 POP_ELEMENT(args);
2649 break;
2651 default: {
2652 rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn)));
2657 if (nsplat > 1) {
2658 int i;
2659 for (i=1; i<nsplat; i++) {
2660 ADD_INSN(args_splat, nd_line(args), concatarray);
2664 if (!LIST_SIZE_ZERO(args_splat)) {
2665 ADD_SEQ(args, args_splat);
2668 if (*flag & VM_CALL_ARGS_BLOCKARG_BIT) {
2669 ADD_SEQ(args, arg_block);
2671 return argc;
2676 compile each node
2678 self: InstructionSequence
2679 node: Ruby compiled node
2680 poped: This node will be poped
2682 static int
2683 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
2685 enum node_type type;
2687 if (node == 0) {
2688 if (!poped) {
2689 debugs("node: NODE_NIL(implicit)\n");
2690 ADD_INSN(ret, iseq->compile_data->last_line, putnil);
2692 return COMPILE_OK;
2695 iseq->compile_data->last_line = nd_line(node);
2696 debug_node_start(node);
2698 type = nd_type(node);
2700 if (node->flags & NODE_FL_NEWLINE) {
2701 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_LINE);
2704 switch (type) {
2705 case NODE_BLOCK:{
2706 while (node && nd_type(node) == NODE_BLOCK) {
2707 COMPILE_(ret, "BLOCK body", node->nd_head,
2708 (node->nd_next == 0 && poped == 0) ? 0 : 1);
2709 node = node->nd_next;
2711 if (node) {
2712 COMPILE_(ret, "BLOCK next", node->nd_next, poped);
2714 break;
2716 case NODE_IF:{
2717 DECL_ANCHOR(cond_seq);
2718 DECL_ANCHOR(then_seq);
2719 DECL_ANCHOR(else_seq);
2720 LABEL *then_label, *else_label, *end_label;
2722 INIT_ANCHOR(cond_seq);
2723 INIT_ANCHOR(then_seq);
2724 INIT_ANCHOR(else_seq);
2725 then_label = NEW_LABEL(nd_line(node));
2726 else_label = NEW_LABEL(nd_line(node));
2727 end_label = NEW_LABEL(nd_line(node));
2729 compile_branch_condition(iseq, cond_seq, node->nd_cond,
2730 then_label, else_label);
2731 COMPILE_(then_seq, "then", node->nd_body, poped);
2732 COMPILE_(else_seq, "else", node->nd_else, poped);
2734 ADD_SEQ(ret, cond_seq);
2736 ADD_LABEL(ret, then_label);
2737 ADD_SEQ(ret, then_seq);
2738 ADD_INSNL(ret, nd_line(node), jump, end_label);
2740 ADD_LABEL(ret, else_label);
2741 ADD_SEQ(ret, else_seq);
2743 ADD_LABEL(ret, end_label);
2745 break;
2747 case NODE_CASE:{
2748 NODE *vals;
2749 NODE *tempnode = node;
2750 LABEL *endlabel, *elselabel;
2751 DECL_ANCHOR(head);
2752 DECL_ANCHOR(body_seq);
2753 DECL_ANCHOR(cond_seq);
2754 VALUE special_literals = rb_ary_new();
2756 INIT_ANCHOR(head);
2757 INIT_ANCHOR(body_seq);
2758 INIT_ANCHOR(cond_seq);
2759 if (node->nd_head == 0) {
2760 COMPILE_(ret, "when", node->nd_body, poped);
2761 break;
2763 COMPILE(head, "case base", node->nd_head);
2765 node = node->nd_body;
2766 type = nd_type(node);
2768 if (type != NODE_WHEN) {
2769 COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
2772 endlabel = NEW_LABEL(nd_line(node));
2773 elselabel = NEW_LABEL(nd_line(node));
2775 ADD_SEQ(ret, head); /* case VAL */
2777 while (type == NODE_WHEN) {
2778 LABEL *l1;
2780 l1 = NEW_LABEL(nd_line(node));
2781 ADD_LABEL(body_seq, l1);
2782 ADD_INSN(body_seq, nd_line(node), pop);
2783 COMPILE_(body_seq, "when body", node->nd_body, poped);
2784 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2786 vals = node->nd_head;
2787 if (vals) {
2788 switch (nd_type(vals)) {
2789 case NODE_ARRAY:
2790 special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals);
2791 break;
2792 case NODE_SPLAT:
2793 case NODE_ARGSCAT:
2794 case NODE_ARGSPUSH:
2795 special_literals = 0;
2796 COMPILE(cond_seq, "when/cond splat", vals);
2797 ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
2798 ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
2799 break;
2800 default:
2801 rb_bug("NODE_CASE: unknown node (%s)",
2802 ruby_node_name(nd_type(vals)));
2805 else {
2806 rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
2809 node = node->nd_next;
2810 if (!node) {
2811 break;
2813 type = nd_type(node);
2815 /* else */
2816 if (node) {
2817 ADD_LABEL(cond_seq, elselabel);
2818 ADD_INSN(cond_seq, nd_line(node), pop);
2819 COMPILE_(cond_seq, "else", node, poped);
2820 ADD_INSNL(cond_seq, nd_line(node), jump, endlabel);
2822 else {
2823 debugs("== else (implicit)\n");
2824 ADD_LABEL(cond_seq, elselabel);
2825 ADD_INSN(cond_seq, nd_line(tempnode), pop);
2826 if (!poped) {
2827 ADD_INSN(cond_seq, nd_line(tempnode), putnil);
2829 ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
2832 if (special_literals) {
2833 ADD_INSN(ret, nd_line(tempnode), dup);
2834 ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch,
2835 special_literals, elselabel);
2836 iseq_add_mark_object_compile_time(iseq, special_literals);
2839 ADD_SEQ(ret, cond_seq);
2840 ADD_SEQ(ret, body_seq);
2841 ADD_LABEL(ret, endlabel);
2842 break;
2844 case NODE_WHEN:{
2845 NODE *vals;
2846 NODE *val;
2847 NODE *orig_node = node;
2848 LABEL *endlabel;
2849 DECL_ANCHOR(body_seq);
2851 INIT_ANCHOR(body_seq);
2852 endlabel = NEW_LABEL(nd_line(node));
2854 while (node && nd_type(node) == NODE_WHEN) {
2855 LABEL *l1 = NEW_LABEL(nd_line(node));
2856 ADD_LABEL(body_seq, l1);
2857 COMPILE_(body_seq, "when", node->nd_body, poped);
2858 ADD_INSNL(body_seq, nd_line(node), jump, endlabel);
2860 vals = node->nd_head;
2861 if (vals && nd_type(vals) == NODE_ARRAY) {
2862 while (vals) {
2863 val = vals->nd_head;
2864 COMPILE(ret, "when2", val);
2865 ADD_INSNL(ret, nd_line(val), branchif, l1);
2866 vals = vals->nd_next;
2869 else if (nd_type(vals) == NODE_SPLAT ||
2870 nd_type(vals) == NODE_ARGSCAT ||
2871 nd_type(vals) == NODE_ARGSPUSH) {
2873 NODE *val = vals->nd_head;
2875 if (nd_type(vals) == NODE_ARGSCAT || nd_type(vals) == NODE_ARGSPUSH) {
2876 NODE *vs = vals->nd_head;
2877 val = vals->nd_body;
2879 while (vs) {
2880 NODE* val = vs->nd_head;
2881 COMPILE(ret, "when/argscat", val);
2882 ADD_INSNL(ret, nd_line(val), branchif, l1);
2883 vs = vs->nd_next;
2887 ADD_INSN(ret, nd_line(val), putnil);
2888 COMPILE(ret, "when2/splat", val);
2889 ADD_INSN1(ret, nd_line(val), checkincludearray, Qfalse);
2890 ADD_INSN(ret, nd_line(val), pop);
2891 ADD_INSNL(ret, nd_line(val), branchif, l1);
2893 else {
2894 rb_bug("err");
2896 node = node->nd_next;
2898 /* else */
2899 COMPILE_(ret, "else", node, poped);
2900 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
2902 ADD_SEQ(ret, body_seq);
2903 ADD_LABEL(ret, endlabel);
2905 break;
2907 case NODE_OPT_N:
2908 case NODE_WHILE:
2909 case NODE_UNTIL:{
2910 LABEL *prev_start_label = iseq->compile_data->start_label;
2911 LABEL *prev_end_label = iseq->compile_data->end_label;
2912 LABEL *prev_redo_label = iseq->compile_data->redo_label;
2913 VALUE prev_loopval_popped = iseq->compile_data->loopval_popped;
2915 struct iseq_compile_data_ensure_node_stack *enlp =
2916 iseq->compile_data->ensure_node_stack;
2918 LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(nd_line(node)); /* next */
2919 LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(nd_line(node)); /* redo */
2920 LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(nd_line(node)); /* break */
2921 LABEL *end_label = NEW_LABEL(nd_line(node));
2923 LABEL *next_catch_label = NEW_LABEL(nd_line(node));
2924 LABEL *tmp_label = NULL;
2926 iseq->compile_data->loopval_popped = 0;
2927 iseq->compile_data->ensure_node_stack = 0;
2929 if (type == NODE_OPT_N || node->nd_state == 1) {
2930 ADD_INSNL(ret, nd_line(node), jump, next_label);
2932 else {
2933 tmp_label = NEW_LABEL(nd_line(node));
2934 ADD_INSNL(ret, nd_line(node), jump, tmp_label);
2936 ADD_INSN(ret, nd_line(node), putnil);
2937 ADD_LABEL(ret, next_catch_label);
2938 ADD_INSN(ret, nd_line(node), pop);
2939 ADD_INSNL(ret, nd_line(node), jump, next_label);
2940 if (tmp_label) ADD_LABEL(ret, tmp_label);
2942 ADD_LABEL(ret, redo_label);
2943 COMPILE_POPED(ret, "while body", node->nd_body);
2944 ADD_LABEL(ret, next_label); /* next */
2946 if (type == NODE_WHILE) {
2947 compile_branch_condition(iseq, ret, node->nd_cond,
2948 redo_label, end_label);
2950 else if (type == NODE_UNTIL) {
2951 /* untile */
2952 compile_branch_condition(iseq, ret, node->nd_cond,
2953 end_label, redo_label);
2955 else {
2956 ADD_CALL_RECEIVER(ret, nd_line(node));
2957 ADD_CALL(ret, nd_line(node), ID2SYM(idGets), INT2FIX(0));
2958 ADD_INSNL(ret, nd_line(node), branchif, redo_label);
2959 /* opt_n */
2962 ADD_LABEL(ret, end_label);
2964 if (node->nd_state == Qundef) {
2965 /* ADD_INSN(ret, nd_line(node), putundef); */
2966 rb_bug("unsupported: putundef");
2968 else {
2969 ADD_INSN(ret, nd_line(node), putnil);
2972 ADD_LABEL(ret, break_label); /* break */
2974 if (poped) {
2975 ADD_INSN(ret, nd_line(node), pop);
2978 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
2979 0, break_label);
2980 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, 0,
2981 next_catch_label);
2982 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
2983 iseq->compile_data->redo_label);
2985 iseq->compile_data->start_label = prev_start_label;
2986 iseq->compile_data->end_label = prev_end_label;
2987 iseq->compile_data->redo_label = prev_redo_label;
2988 iseq->compile_data->loopval_popped = prev_loopval_popped;
2989 iseq->compile_data->ensure_node_stack = enlp;
2990 break;
2992 case NODE_ITER:
2993 case NODE_FOR:{
2994 VALUE prevblock = iseq->compile_data->current_block;
2995 LABEL *retry_label = NEW_LABEL(nd_line(node));
2996 LABEL *retry_end_l = NEW_LABEL(nd_line(node));
2997 ID mid = 0;
2999 ADD_LABEL(ret, retry_label);
3000 if (nd_type(node) == NODE_FOR) {
3001 COMPILE(ret, "iter caller (for)", node->nd_iter);
3003 iseq->compile_data->current_block =
3004 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3005 ISEQ_TYPE_BLOCK);
3007 mid = idEach;
3008 ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
3009 iseq->compile_data->current_block, INT2FIX(0));
3011 else {
3012 iseq->compile_data->current_block =
3013 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3014 ISEQ_TYPE_BLOCK);
3015 COMPILE(ret, "iter caller", node->nd_iter);
3017 ADD_LABEL(ret, retry_end_l);
3019 if (poped) {
3020 ADD_INSN(ret, nd_line(node), pop);
3023 iseq->compile_data->current_block = prevblock;
3025 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
3027 break;
3029 case NODE_BREAK:{
3030 unsigned long level = 0;
3032 if (iseq->compile_data->redo_label != 0) {
3033 /* while/until */
3034 LABEL *splabel = NEW_LABEL(0);
3035 ADD_LABEL(ret, splabel);
3036 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3037 COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
3038 add_ensure_iseq(ret, iseq);
3039 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3040 ADD_ADJUST_RESTORE(ret, splabel);
3042 if (!poped) {
3043 ADD_INSN(ret, nd_line(node), putnil);
3046 else if (iseq->type == ISEQ_TYPE_BLOCK) {
3047 break_by_insn:
3048 /* escape from block */
3049 COMPILE(ret, "break val (block)", node->nd_stts);
3050 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x02) /* TAG_BREAK */ );
3051 if (poped) {
3052 ADD_INSN(ret, nd_line(node), pop);
3055 else if (iseq->type == ISEQ_TYPE_EVAL) {
3056 break_in_eval:
3057 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
3059 else {
3060 rb_iseq_t *ip = iseq->parent_iseq;
3061 while (ip) {
3062 level++;
3063 if (ip->compile_data->redo_label != 0) {
3064 level = 0x8000;
3065 if (ip->compile_data->loopval_popped == 0) {
3066 /* need value */
3067 level |= 0x4000;
3069 goto break_by_insn;
3071 else if (ip->type == ISEQ_TYPE_BLOCK) {
3072 level <<= 16;
3073 goto break_by_insn;
3075 else if (ip->type == ISEQ_TYPE_EVAL) {
3076 goto break_in_eval;
3078 ip = ip->parent_iseq;
3080 COMPILE_ERROR((ERROR_ARGS "Invalid break"));
3082 break;
3084 case NODE_NEXT:{
3085 unsigned long level = 0;
3087 if (iseq->compile_data->redo_label != 0) {
3088 LABEL *splabel = NEW_LABEL(0);
3089 debugs("next in while loop\n");
3090 ADD_LABEL(ret, splabel);
3091 COMPILE(ret, "next val/valid syntax?", node->nd_stts);
3092 add_ensure_iseq(ret, iseq);
3093 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3094 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3095 ADD_ADJUST_RESTORE(ret, splabel);
3097 else if (iseq->compile_data->end_label) {
3098 LABEL *splabel = NEW_LABEL(0);
3099 debugs("next in block\n");
3100 ADD_LABEL(ret, splabel);
3101 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3102 COMPILE(ret, "next val", node->nd_stts);
3103 add_ensure_iseq(ret, iseq);
3104 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label);
3105 ADD_ADJUST_RESTORE(ret, splabel);
3107 if (!poped) {
3108 ADD_INSN(ret, nd_line(node), putnil);
3111 else if (iseq->type == ISEQ_TYPE_EVAL) {
3112 next_in_eval:
3113 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
3115 else {
3116 rb_iseq_t *ip;
3117 ip = iseq;
3118 while (ip) {
3119 level = 0x8000 | 0x4000;
3120 if (ip->compile_data->redo_label != 0) {
3121 /* while loop */
3122 break;
3124 else if (ip->type == ISEQ_TYPE_BLOCK) {
3125 break;
3127 else if (ip->type == ISEQ_TYPE_EVAL) {
3128 goto next_in_eval;
3130 ip = ip->parent_iseq;
3132 if (ip != 0) {
3133 COMPILE(ret, "next val", node->nd_stts);
3134 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x03) /* TAG_NEXT */ );
3136 if (poped) {
3137 ADD_INSN(ret, nd_line(node), pop);
3140 else {
3141 COMPILE_ERROR((ERROR_ARGS "Invalid next"));
3144 break;
3146 case NODE_REDO:{
3147 if (iseq->compile_data->redo_label) {
3148 LABEL *splabel = NEW_LABEL(0);
3149 debugs("redo in while");
3150 ADD_LABEL(ret, splabel);
3151 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label);
3152 add_ensure_iseq(ret, iseq);
3153 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->redo_label);
3154 ADD_ADJUST_RESTORE(ret, splabel);
3156 else if (iseq->type == ISEQ_TYPE_EVAL) {
3157 redo_in_eval:
3158 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
3160 else if (iseq->compile_data->start_label) {
3161 LABEL *splabel = NEW_LABEL(0);
3163 debugs("redo in block");
3164 ADD_LABEL(ret, splabel);
3165 add_ensure_iseq(ret, iseq);
3166 ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label);
3167 ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label);
3168 ADD_ADJUST_RESTORE(ret, splabel);
3170 if (!poped) {
3171 ADD_INSN(ret, nd_line(node), putnil);
3174 else {
3175 rb_iseq_t *ip;
3176 unsigned long level;
3177 level = 0x8000 | 0x4000;
3178 ip = iseq;
3179 while (ip) {
3180 if (ip->compile_data->redo_label != 0) {
3181 break;
3183 else if (ip->type == ISEQ_TYPE_BLOCK) {
3184 break;
3186 else if (ip->type == ISEQ_TYPE_EVAL) {
3187 goto redo_in_eval;
3189 ip = ip->parent_iseq;
3191 if (ip != 0) {
3192 ADD_INSN(ret, nd_line(node), putnil);
3193 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x05) /* TAG_REDO */ );
3195 if (poped) {
3196 ADD_INSN(ret, nd_line(node), pop);
3199 else {
3200 COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
3203 break;
3205 case NODE_RETRY:{
3206 if (iseq->type == ISEQ_TYPE_RESCUE) {
3207 ADD_INSN(ret, nd_line(node), putnil);
3208 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x04) /* TAG_RETRY */ );
3210 if (poped) {
3211 ADD_INSN(ret, nd_line(node), pop);
3214 else {
3215 COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
3217 break;
3219 case NODE_BEGIN:{
3220 COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
3221 break;
3223 case NODE_RESCUE:{
3224 LABEL *lstart = NEW_LABEL(nd_line(node));
3225 LABEL *lend = NEW_LABEL(nd_line(node));
3226 LABEL *lcont = NEW_LABEL(nd_line(node));
3227 VALUE rescue = NEW_CHILD_ISEQVAL(
3228 node->nd_resq,
3229 rb_str_concat(rb_str_new2("rescue in "), iseq->name),
3230 ISEQ_TYPE_RESCUE);
3232 ADD_LABEL(ret, lstart);
3233 COMPILE(ret, "rescue head", node->nd_head);
3234 ADD_LABEL(ret, lend);
3235 if (node->nd_else) {
3236 ADD_INSN(ret, nd_line(node), pop);
3237 COMPILE(ret, "rescue else", node->nd_else);
3239 ADD_INSN(ret, nd_line(node), nop);
3240 ADD_LABEL(ret, lcont);
3242 if (poped) {
3243 ADD_INSN(ret, nd_line(node), pop);
3246 /* resgister catch entry */
3247 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
3248 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
3249 break;
3251 case NODE_RESBODY:{
3252 NODE *resq = node;
3253 NODE *narg;
3254 LABEL *label_miss, *label_hit;
3256 while (resq) {
3257 label_miss = NEW_LABEL(nd_line(node));
3258 label_hit = NEW_LABEL(nd_line(node));
3260 narg = resq->nd_args;
3261 if (narg) {
3262 switch (nd_type(narg)) {
3263 case NODE_ARRAY:
3264 while (narg) {
3265 COMPILE(ret, "rescue arg", narg->nd_head);
3266 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
3267 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3268 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3269 narg = narg->nd_next;
3271 break;
3272 case NODE_SPLAT:
3273 case NODE_ARGSCAT:
3274 case NODE_ARGSPUSH:
3275 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
3276 COMPILE(ret, "rescue/cond splat", narg);
3277 ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
3278 ADD_INSN(ret, nd_line(node), swap);
3279 ADD_INSN(ret, nd_line(node), pop);
3280 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3281 break;
3282 default:
3283 rb_bug("NODE_RESBODY: unknown node (%s)",
3284 ruby_node_name(nd_type(narg)));
3287 else {
3288 ADD_INSN1(ret, nd_line(node), putobject,
3289 rb_eStandardError);
3290 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
3291 ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
3292 ADD_INSNL(ret, nd_line(node), branchif, label_hit);
3294 ADD_INSNL(ret, nd_line(node), jump, label_miss);
3295 ADD_LABEL(ret, label_hit);
3296 COMPILE(ret, "resbody body", resq->nd_body);
3297 if (iseq->compile_data->option->tailcall_optimization) {
3298 ADD_INSN(ret, nd_line(node), nop);
3300 ADD_INSN(ret, nd_line(node), leave);
3301 ADD_LABEL(ret, label_miss);
3302 resq = resq->nd_head;
3304 break;
3306 case NODE_ENSURE:{
3307 DECL_ANCHOR(ensr);
3308 VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
3309 rb_str_concat(rb_str_new2
3310 ("ensure in "),
3311 iseq->name),
3312 ISEQ_TYPE_ENSURE);
3313 LABEL *lstart = NEW_LABEL(nd_line(node));
3314 LABEL *lend = NEW_LABEL(nd_line(node));
3315 LABEL *lcont = NEW_LABEL(nd_line(node));
3316 struct ensure_range er = { 0 };
3317 struct iseq_compile_data_ensure_node_stack enl;
3318 struct ensure_range *erange;
3320 INIT_ANCHOR(ensr);
3321 er.begin = lstart;
3322 er.end = lend;
3323 enl.ensure_node = node->nd_ensr;
3324 enl.prev = iseq->compile_data->ensure_node_stack; /* prev */
3325 enl.erange = &er;
3326 COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
3328 iseq->compile_data->ensure_node_stack = &enl;
3330 ADD_LABEL(ret, lstart);
3331 COMPILE_(ret, "ensure head", node->nd_head, poped);
3332 ADD_LABEL(ret, lend);
3333 if (ensr->anchor.next == 0) {
3334 ADD_INSN(ret, nd_line(node), nop);
3336 else {
3337 ADD_SEQ(ret, ensr);
3339 ADD_LABEL(ret, lcont);
3341 erange = iseq->compile_data->ensure_node_stack->erange;
3342 while (erange) {
3343 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
3344 ensure, lcont);
3345 erange = erange->next;
3347 iseq->compile_data->ensure_node_stack = enl.prev;
3348 break;
3351 case NODE_AND:
3352 case NODE_OR:{
3353 LABEL *end_label = NEW_LABEL(nd_line(node));
3354 COMPILE(ret, "nd_1st", node->nd_1st);
3355 if (!poped) {
3356 ADD_INSN(ret, nd_line(node), dup);
3358 if (type == NODE_AND) {
3359 ADD_INSNL(ret, nd_line(node), branchunless, end_label);
3361 else {
3362 ADD_INSNL(ret, nd_line(node), branchif, end_label);
3364 if (!poped) {
3365 ADD_INSN(ret, nd_line(node), pop);
3367 COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
3368 ADD_LABEL(ret, end_label);
3369 break;
3372 case NODE_MASGN:{
3373 compile_massign(iseq, ret, node, poped);
3374 break;
3377 case NODE_LASGN:{
3378 ID id = node->nd_vid;
3379 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3381 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
3382 COMPILE(ret, "rvalue", node->nd_value);
3384 if (!poped) {
3385 ADD_INSN(ret, nd_line(node), dup);
3387 ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx));
3389 break;
3391 case NODE_DASGN:
3392 case NODE_DASGN_CURR:{
3393 int idx, lv, ls;
3394 COMPILE(ret, "dvalue", node->nd_value);
3395 debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
3397 if (!poped) {
3398 ADD_INSN(ret, nd_line(node), dup);
3401 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
3403 if (idx < 0) {
3404 rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
3407 ADD_INSN2(ret, nd_line(node), setdynamic,
3408 INT2FIX(ls - idx), INT2FIX(lv));
3409 break;
3411 case NODE_GASGN:{
3412 COMPILE(ret, "lvalue", node->nd_value);
3414 if (!poped) {
3415 ADD_INSN(ret, nd_line(node), dup);
3417 ADD_INSN1(ret, nd_line(node), setglobal,
3418 (((long)node->nd_entry) | 1));
3419 break;
3421 case NODE_IASGN:
3422 case NODE_IASGN2:{
3423 COMPILE(ret, "lvalue", node->nd_value);
3424 if (!poped) {
3425 ADD_INSN(ret, nd_line(node), dup);
3427 ADD_INSN1(ret, nd_line(node), setinstancevariable,
3428 ID2SYM(node->nd_vid));
3429 break;
3431 case NODE_CDECL:{
3432 COMPILE(ret, "lvalue", node->nd_value);
3434 if (!poped) {
3435 ADD_INSN(ret, nd_line(node), dup);
3438 if (node->nd_vid) {
3439 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
3440 ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_vid));
3442 else {
3443 compile_cpath(ret, iseq, node->nd_else);
3444 ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_else->nd_mid));
3446 break;
3448 case NODE_CVASGN:{
3449 COMPILE(ret, "cvasgn val", node->nd_value);
3450 if (!poped) {
3451 ADD_INSN(ret, nd_line(node), dup);
3453 ADD_INSN1(ret, nd_line(node), setclassvariable,
3454 ID2SYM(node->nd_vid));
3455 break;
3457 case NODE_OP_ASGN1: {
3458 DECL_ANCHOR(args);
3459 VALUE argc;
3460 unsigned long flag = 0;
3461 ID id = node->nd_mid;
3464 * a[x] (op)= y
3466 * eval a # a
3467 * eval x # a x
3468 * dupn 2 # a x a x
3469 * send :[] # a x a[x]
3470 * eval y # a x a[x] y
3471 * send op # a x a[x]+y
3472 * send []= # ret
3476 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
3477 * NODE_OP_ASGN nd_recv
3478 * nd_args->nd_head
3479 * nd_args->nd_body
3480 * nd_mid
3483 COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
3484 if (nd_type(node->nd_args->nd_body) != NODE_ZARRAY) {
3485 INIT_ANCHOR(args);
3486 argc = setup_args(iseq, args, node->nd_args->nd_body, &flag);
3487 ADD_SEQ(ret, args);
3489 else {
3490 argc = INT2FIX(0);
3492 ADD_INSN1(ret, nd_line(node), dupn, INT2FIX(FIX2INT(argc)+1));
3493 ADD_SEND_R(ret, nd_line(node), ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
3495 if (id == 0 || id == 1) {
3496 /* 0: or, 1: and
3497 a[x] ||= y
3499 unless/if a[x]
3500 a[x]= y
3501 else
3505 LABEL *label = NEW_LABEL(nd_line(node));
3506 LABEL *lfin = NEW_LABEL(nd_line(node));
3508 if (id == 0) {
3509 /* or */
3510 ADD_INSN(ret, nd_line(node), dup);
3511 ADD_INSNL(ret, nd_line(node), branchif, label);
3512 ADD_INSN(ret, nd_line(node), pop);
3514 else {
3515 /* and */
3516 ADD_INSN(ret, nd_line(node), dup);
3517 ADD_INSNL(ret, nd_line(node), branchunless, label);
3518 ADD_INSN(ret, nd_line(node), pop);
3521 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3522 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3523 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3524 ADD_INSN(ret, nd_line(node), concatarray);
3525 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3526 argc, Qfalse, LONG2FIX(flag));
3528 else {
3529 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3530 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3532 ADD_INSNL(ret, nd_line(node), jump, lfin);
3533 ADD_LABEL(ret, label);
3534 if (id == 0 || id == 1) { /* 0: or, 1: and */
3535 ADD_INSN(ret, nd_line(node), swap);
3536 ADD_INSN(ret, nd_line(node), pop);
3537 ADD_INSN(ret, nd_line(node), swap);
3538 ADD_INSN(ret, nd_line(node), pop);
3540 ADD_LABEL(ret, lfin);
3542 else {
3543 COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head);
3544 ADD_SEND(ret, nd_line(node), ID2SYM(id), INT2FIX(1));
3545 if (flag & VM_CALL_ARGS_SPLAT_BIT) {
3546 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
3547 ADD_INSN(ret, nd_line(node), concatarray);
3548 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3549 argc, Qfalse, LONG2FIX(flag));
3551 else {
3552 ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
3553 INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag));
3557 if (poped) {
3558 ADD_INSN(ret, nd_line(node), pop);
3561 break;
3563 case NODE_OP_ASGN2:{
3564 ID atype = node->nd_next->nd_mid;
3565 LABEL *lfin = NEW_LABEL(nd_line(node));
3566 LABEL *lcfin = NEW_LABEL(nd_line(node));
3568 class C; attr_accessor :c; end
3569 r = C.new
3570 r.a &&= v # asgn2
3572 eval r # r
3573 dup # r r
3574 eval r.a # r o
3576 # or
3577 dup # r o o
3578 if lcfin # r o
3579 pop # r
3580 eval v # r v
3581 send a= # v
3582 jump lfin # v
3584 lcfin: # r o
3585 swap # o r
3586 pop # o
3588 lfin: # v
3590 # and
3591 dup # r o o
3592 unless lcfin
3593 pop # r
3594 eval v # r v
3595 send a= # v
3596 jump lfin # v
3598 # others
3599 eval v # r o v
3600 send ?? # r w
3601 send a= # w
3605 COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
3606 ADD_INSN(ret, nd_line(node), dup);
3607 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_vid),
3608 INT2FIX(0));
3610 if (atype == 0 || atype == 1) { /* 0: OR or 1: AND */
3611 ADD_INSN(ret, nd_line(node), dup);
3612 if (atype == 0) {
3613 ADD_INSNL(ret, nd_line(node), branchif, lcfin);
3615 else {
3616 ADD_INSNL(ret, nd_line(node), branchunless, lcfin);
3618 ADD_INSN(ret, nd_line(node), pop);
3619 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3620 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3621 INT2FIX(1));
3622 ADD_INSNL(ret, nd_line(node), jump, lfin);
3624 ADD_LABEL(ret, lcfin);
3625 ADD_INSN(ret, nd_line(node), swap);
3626 ADD_INSN(ret, nd_line(node), pop);
3628 ADD_LABEL(ret, lfin);
3630 else {
3631 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
3632 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_mid),
3633 INT2FIX(1));
3634 ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid),
3635 INT2FIX(1));
3638 if (poped) {
3639 /* we can apply more optimize */
3640 ADD_INSN(ret, nd_line(node), pop);
3642 break;
3644 case NODE_OP_ASGN_AND:
3645 case NODE_OP_ASGN_OR:{
3646 LABEL *lfin = NEW_LABEL(nd_line(node));
3647 LABEL *lassign;
3649 if (nd_type(node) == NODE_OP_ASGN_OR) {
3650 LABEL *lfinish[2];
3651 lfinish[0] = lfin;
3652 lfinish[1] = 0;
3653 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
3654 lassign = lfinish[1];
3655 if (!lassign) {
3656 lassign = NEW_LABEL(nd_line(node));
3658 ADD_INSNL(ret, nd_line(node), branchunless, lassign);
3660 else {
3661 lassign = NEW_LABEL(nd_line(node));
3664 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
3665 ADD_INSN(ret, nd_line(node), dup);
3667 if (nd_type(node) == NODE_OP_ASGN_AND) {
3668 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
3670 else {
3671 ADD_INSNL(ret, nd_line(node), branchif, lfin);
3674 ADD_INSN(ret, nd_line(node), pop);
3675 ADD_LABEL(ret, lassign);
3676 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
3677 ADD_LABEL(ret, lfin);
3679 if (poped) {
3680 /* we can apply more optimize */
3681 ADD_INSN(ret, nd_line(node), pop);
3683 break;
3685 case NODE_CALL:
3686 case NODE_FCALL:
3687 case NODE_VCALL:{ /* VCALL: variable or call */
3689 call: obj.method(...)
3690 fcall: func(...)
3691 vcall: func
3693 DECL_ANCHOR(recv);
3694 DECL_ANCHOR(args);
3695 ID mid = node->nd_mid;
3696 VALUE argc;
3697 unsigned long flag = 0;
3698 VALUE parent_block = iseq->compile_data->current_block;
3699 iseq->compile_data->current_block = Qfalse;
3701 INIT_ANCHOR(recv);
3702 INIT_ANCHOR(args);
3703 #if SUPPORT_JOKE
3704 if (nd_type(node) == NODE_VCALL) {
3705 if (mid == idBitblt) {
3706 ADD_INSN(ret, nd_line(node), bitblt);
3707 break;
3709 else if (mid == idAnswer) {
3710 ADD_INSN(ret, nd_line(node), answer);
3711 break;
3714 /* only joke */
3716 ID goto_id;
3717 ID label_id;
3718 VALUE label;
3719 VALUE label_sym;
3722 CONST_ID(goto_id, "__goto__");
3723 CONST_ID(label_id, "__label__");
3725 if (nd_type(node) == NODE_FCALL &&
3726 (mid == goto_id || mid == label_id)) {
3727 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
3728 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
3730 label_sym = label = node->nd_args->nd_head->nd_lit;
3731 if ((label =
3732 rb_hash_aref(iseq->compile_data,
3733 label_sym)) == Qnil) {
3734 rb_hash_aset(iseq->compile_data, label_sym,
3735 label = NEW_LABEL(nd_line(node)));
3738 else {
3739 rb_bug("invalid goto/label format");
3743 if (mid == goto_id) {
3744 ADD_INSNL(ret, nd_line(node), jump, label);
3746 else {
3747 ADD_LABEL(ret, label);
3749 break;
3752 #endif
3753 /* reciever */
3754 if (type == NODE_CALL) {
3755 COMPILE(recv, "recv", node->nd_recv);
3757 else if (type == NODE_FCALL || type == NODE_VCALL) {
3758 ADD_CALL_RECEIVER(recv, nd_line(node));
3761 /* args */
3762 if (nd_type(node) != NODE_VCALL) {
3763 argc = setup_args(iseq, args, node->nd_args, &flag);
3765 else {
3766 argc = INT2FIX(0);
3769 ADD_SEQ(ret, recv);
3770 ADD_SEQ(ret, args);
3772 debugp_param("call args argc", argc);
3773 debugp_param("call method", ID2SYM(mid));
3775 switch (nd_type(node)) {
3776 case NODE_VCALL:
3777 flag |= VM_CALL_VCALL_BIT;
3778 /* VCALL is funcall, so fall through */
3779 case NODE_FCALL:
3780 flag |= VM_CALL_FCALL_BIT;
3783 ADD_SEND_R(ret, nd_line(node), ID2SYM(mid),
3784 argc, parent_block, LONG2FIX(flag));
3786 if (poped) {
3787 ADD_INSN(ret, nd_line(node), pop);
3789 break;
3791 case NODE_SUPER:
3792 case NODE_ZSUPER:{
3793 DECL_ANCHOR(args);
3794 VALUE argc;
3795 unsigned long flag = 0;
3796 VALUE parent_block = iseq->compile_data->current_block;
3798 INIT_ANCHOR(args);
3799 iseq->compile_data->current_block = Qfalse;
3800 if (nd_type(node) == NODE_SUPER) {
3801 argc = setup_args(iseq, args, node->nd_args, &flag);
3803 else {
3804 /* NODE_ZSUPER */
3805 int i;
3806 rb_iseq_t *liseq = iseq->local_iseq;
3808 argc = INT2FIX(liseq->argc);
3810 /* normal arguments */
3811 for (i = 0; i < liseq->argc; i++) {
3812 int idx = liseq->local_size - i;
3813 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3816 if (!liseq->arg_simple) {
3817 if (liseq->arg_opts) {
3818 /* optional arguments */
3819 int j;
3820 for (j = 0; j < liseq->arg_opts - 1; j++) {
3821 int idx = liseq->local_size - (i + j);
3822 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3824 i += j;
3825 argc = INT2FIX(i);
3828 if (liseq->arg_rest != -1) {
3829 /* rest argument */
3830 int idx = liseq->local_size - liseq->arg_rest;
3831 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3832 argc = INT2FIX(liseq->arg_rest + 1);
3833 flag |= VM_CALL_ARGS_SPLAT_BIT;
3836 if (liseq->arg_post_len) {
3837 /* post arguments */
3838 int post_len = liseq->arg_post_len;
3839 int post_start = liseq->arg_post_start;
3841 if (liseq->arg_rest != -1) {
3842 int j;
3843 for (j=0; j<post_len; j++) {
3844 int idx = liseq->local_size - (post_start + j);
3845 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3847 ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j));
3848 ADD_INSN (args, nd_line(node), concatarray);
3849 /* argc is setteled at above */
3851 else {
3852 int j;
3853 for (j=0; j<post_len; j++) {
3854 int idx = liseq->local_size - (post_start + j);
3855 ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
3857 argc = INT2FIX(post_len + post_start);
3863 /* dummy reciever */
3864 ADD_INSN1(ret, nd_line(node), putobject,
3865 nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
3866 ADD_SEQ(ret, args);
3867 ADD_INSN3(ret, nd_line(node), invokesuper,
3868 argc, parent_block, LONG2FIX(flag));
3870 if (poped) {
3871 ADD_INSN(ret, nd_line(node), pop);
3873 break;
3875 case NODE_ARRAY:{
3876 compile_array_(iseq, ret, node, Qtrue, poped);
3877 break;
3879 case NODE_ZARRAY:{
3880 if (!poped) {
3881 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(0));
3883 break;
3885 case NODE_VALUES:{
3886 NODE *n = node;
3887 while (n) {
3888 COMPILE(ret, "values item", n->nd_head);
3889 n = n->nd_next;
3891 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(node->nd_alen));
3892 if (poped) {
3893 ADD_INSN(ret, nd_line(node), pop);
3895 break;
3897 case NODE_HASH:{
3898 DECL_ANCHOR(list);
3899 VALUE size = 0;
3900 int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
3902 INIT_ANCHOR(list);
3903 switch (type) {
3904 case NODE_ARRAY:{
3905 compile_array(iseq, list, node->nd_head, Qfalse);
3906 size = OPERAND_AT(POP_ELEMENT(list), 0);
3907 ADD_SEQ(ret, list);
3908 break;
3910 case NODE_ZARRAY:
3911 size = INT2FIX(0);
3912 break;
3914 default:
3915 rb_bug("can't make hash with this node: %s", ruby_node_name(type));
3918 ADD_INSN1(ret, nd_line(node), newhash, size);
3920 if (poped) {
3921 ADD_INSN(ret, nd_line(node), pop);
3923 break;
3925 case NODE_RETURN:{
3926 rb_iseq_t *is = iseq;
3928 while (is) {
3929 if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) {
3930 COMPILE_ERROR((ERROR_ARGS "Invalid return"));
3931 break;
3933 else {
3934 LABEL *splabel = 0;
3936 if (is->type == ISEQ_TYPE_METHOD) {
3937 splabel = NEW_LABEL(0);
3938 ADD_LABEL(ret, splabel);
3939 ADD_ADJUST(ret, nd_line(node), 0);
3942 COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
3944 if (is->type == ISEQ_TYPE_METHOD) {
3945 add_ensure_iseq(ret, iseq);
3946 ADD_INSN(ret, nd_line(node), leave);
3947 ADD_ADJUST_RESTORE(ret, splabel);
3949 if (!poped) {
3950 ADD_INSN(ret, nd_line(node), putnil);
3953 else {
3954 ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x01) /* TAG_RETURN */ );
3955 if (poped) {
3956 ADD_INSN(ret, nd_line(node), pop);
3959 break;
3962 break;
3964 case NODE_YIELD:{
3965 DECL_ANCHOR(args);
3966 VALUE argc;
3967 unsigned long flag = 0;
3969 INIT_ANCHOR(args);
3970 if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) {
3971 COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
3974 if (node->nd_head) {
3975 argc = setup_args(iseq, args, node->nd_head, &flag);
3977 else {
3978 argc = INT2FIX(0);
3981 ADD_SEQ(ret, args);
3982 ADD_INSN2(ret, nd_line(node), invokeblock, argc, LONG2FIX(flag));
3984 if (poped) {
3985 ADD_INSN(ret, nd_line(node), pop);
3987 break;
3989 case NODE_LVAR:{
3990 if (!poped) {
3991 ID id = node->nd_vid;
3992 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3994 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
3995 ADD_INSN1(ret, nd_line(node), getlocal, INT2FIX(idx));
3997 break;
3999 case NODE_DVAR:{
4000 int lv, idx, ls;
4001 debugi("nd_vid", node->nd_vid);
4002 if (!poped) {
4003 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
4004 if (idx < 0) {
4005 rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
4007 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(ls - idx), INT2FIX(lv));
4009 break;
4011 case NODE_GVAR:{
4012 ADD_INSN1(ret, nd_line(node), getglobal,
4013 (((long)node->nd_entry) | 1));
4014 if (poped) {
4015 ADD_INSN(ret, nd_line(node), pop);
4017 break;
4019 case NODE_IVAR:{
4020 debugi("nd_vid", node->nd_vid);
4021 if (!poped) {
4022 ADD_INSN1(ret, nd_line(node), getinstancevariable,
4023 ID2SYM(node->nd_vid));
4025 break;
4027 case NODE_CONST:{
4028 debugi("nd_vid", node->nd_vid);
4030 if (iseq->compile_data->option->inline_const_cache) {
4031 LABEL *lstart = NEW_LABEL(nd_line(node));
4032 LABEL *lend = NEW_LABEL(nd_line(node));
4034 ADD_LABEL(ret, lstart);
4035 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4036 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4037 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4038 ADD_LABEL(ret, lend);
4040 else {
4041 ADD_INSN(ret, nd_line(node), putnil);
4042 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4045 if (poped) {
4046 ADD_INSN(ret, nd_line(node), pop);
4048 break;
4050 case NODE_CVAR:{
4051 if (!poped) {
4052 ADD_INSN1(ret, nd_line(node), getclassvariable,
4053 ID2SYM(node->nd_vid));
4055 break;
4057 case NODE_NTH_REF:{
4058 if (!poped) {
4059 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4060 INT2FIX(node->nd_nth << 1));
4062 break;
4064 case NODE_BACK_REF:{
4065 if (!poped) {
4066 ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */,
4067 INT2FIX(0x01 | (node->nd_nth << 1)));
4069 break;
4071 case NODE_MATCH:
4072 case NODE_MATCH2:
4073 case NODE_MATCH3:{
4074 DECL_ANCHOR(recv);
4075 DECL_ANCHOR(val);
4077 INIT_ANCHOR(recv);
4078 INIT_ANCHOR(val);
4079 switch(nd_type(node)) {
4080 case NODE_MATCH:
4081 ADD_INSN1(recv, nd_line(node), putobject, node->nd_lit);
4082 ADD_INSN2(val, nd_line(node), getspecial, INT2FIX(0),
4083 INT2FIX(0));
4084 break;
4085 case NODE_MATCH2:
4086 COMPILE(recv, "reciever", node->nd_recv);
4087 COMPILE(val, "value", node->nd_value);
4088 break;
4089 case NODE_MATCH3:
4090 COMPILE(recv, "reciever", node->nd_value);
4091 COMPILE(val, "value", node->nd_recv);
4092 break;
4095 if (iseq->compile_data->option->specialized_instruction) {
4096 /* TODO: detect by node */
4097 if (recv->last == recv->anchor.next &&
4098 INSN_OF(recv->last) == BIN(putobject) &&
4099 nd_type(node) == NODE_MATCH2) {
4100 ADD_SEQ(ret, val);
4101 ADD_INSN1(ret, nd_line(node), opt_regexpmatch1,
4102 OPERAND_AT(recv->last, 0));
4104 else {
4105 ADD_SEQ(ret, recv);
4106 ADD_SEQ(ret, val);
4107 ADD_INSN(ret, nd_line(node), opt_regexpmatch2);
4110 else {
4111 ADD_SEQ(ret, recv);
4112 ADD_SEQ(ret, val);
4113 ADD_SEND(ret, nd_line(node), ID2SYM(idEqTilde), INT2FIX(1));
4116 if (poped) {
4117 ADD_INSN(ret, nd_line(node), pop);
4119 break;
4121 case NODE_LIT:{
4122 debugp_param("lit", node->nd_lit);
4123 if (!poped) {
4124 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4126 break;
4128 case NODE_STR:{
4129 debugp_param("nd_lit", node->nd_lit);
4130 if (!poped) {
4131 ADD_INSN1(ret, nd_line(node), putstring, node->nd_lit);
4133 break;
4135 case NODE_DSTR:{
4136 compile_dstr(iseq, ret, node);
4138 if (poped) {
4139 ADD_INSN(ret, nd_line(node), pop);
4141 break;
4143 case NODE_XSTR:{
4144 ADD_CALL_RECEIVER(ret, nd_line(node));
4145 ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
4146 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4148 if (poped) {
4149 ADD_INSN(ret, nd_line(node), pop);
4151 break;
4153 case NODE_DXSTR:{
4154 ADD_CALL_RECEIVER(ret, nd_line(node));
4155 compile_dstr(iseq, ret, node);
4156 ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1));
4158 if (poped) {
4159 ADD_INSN(ret, nd_line(node), pop);
4161 break;
4163 case NODE_EVSTR:{
4164 COMPILE(ret, "nd_body", node->nd_body);
4166 if (poped) {
4167 ADD_INSN(ret, nd_line(node), pop);
4169 else {
4170 ADD_INSN(ret, nd_line(node), tostring);
4172 break;
4174 case NODE_DREGX:{
4175 compile_dregx(iseq, ret, node);
4177 if (poped) {
4178 ADD_INSN(ret, nd_line(node), pop);
4180 break;
4182 case NODE_DREGX_ONCE:{
4183 /* TODO: once? */
4184 LABEL *lstart = NEW_LABEL(nd_line(node));
4185 LABEL *lend = NEW_LABEL(nd_line(node));
4187 ADD_LABEL(ret, lstart);
4188 ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend);
4189 ADD_INSN(ret, nd_line(node), pop);
4191 compile_dregx(iseq, ret, node);
4193 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4194 ADD_LABEL(ret, lend);
4196 if (poped) {
4197 ADD_INSN(ret, nd_line(node), pop);
4199 break;
4201 case NODE_ARGSCAT:{
4202 COMPILE(ret, "argscat head", node->nd_head);
4203 COMPILE(ret, "argscat body", node->nd_body);
4204 ADD_INSN(ret, nd_line(node), concatarray);
4205 break;
4207 case NODE_ARGSPUSH:{
4208 COMPILE(ret, "arsgpush head", node->nd_head);
4209 COMPILE(ret, "argspush body", node->nd_body);
4210 ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
4211 ADD_INSN(ret, nd_line(node), concatarray);
4212 break;
4214 case NODE_SPLAT:{
4215 COMPILE(ret, "splat", node->nd_head);
4216 ADD_INSN1(ret, nd_line(node), splatarray, Qfalse);
4218 if (poped) {
4219 ADD_INSN(ret, nd_line(node), pop);
4221 break;
4223 case NODE_DEFN:{
4224 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4225 rb_str_dup(rb_id2str(node->nd_mid)),
4226 ISEQ_TYPE_METHOD);
4228 debugp_param("defn/iseq", iseqval);
4230 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4231 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4232 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid));
4233 ADD_INSN1(ret, nd_line(node), putiseq, iseqval);
4234 ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3));
4236 if (poped) {
4237 ADD_INSN(ret, nd_line(node), pop);
4240 debugp_param("defn", iseqval);
4241 break;
4243 case NODE_DEFS:{
4244 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4245 rb_str_dup(rb_id2str(node->nd_mid)),
4246 ISEQ_TYPE_METHOD);
4248 debugp_param("defs/iseq", iseqval);
4250 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4251 COMPILE(ret, "defs: recv", node->nd_recv);
4252 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid));
4253 ADD_INSN1(ret, nd_line(node), putiseq, iseqval);
4254 ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_singleton_method), INT2FIX(3));
4256 if (poped) {
4257 ADD_INSN(ret, nd_line(node), pop);
4259 break;
4261 case NODE_ALIAS:{
4262 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4263 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4264 COMPILE(ret, "alias arg1", node->u1.node);
4265 COMPILE(ret, "alias arg2", node->u2.node);
4266 ADD_SEND(ret, nd_line(node), ID2SYM(id_core_set_method_alias), INT2FIX(3));
4268 if (poped) {
4269 ADD_INSN(ret, nd_line(node), pop);
4271 break;
4273 case NODE_VALIAS:{
4274 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4275 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id));
4276 ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id));
4277 ADD_SEND(ret, nd_line(node), ID2SYM(id_core_set_variable_alias), INT2FIX(2));
4279 if (poped) {
4280 ADD_INSN(ret, nd_line(node), pop);
4282 break;
4284 case NODE_UNDEF:{
4285 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4286 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4287 COMPILE(ret, "undef arg", node->u2.node);
4288 ADD_SEND(ret, nd_line(node), ID2SYM(id_core_undef_method), INT2FIX(2));
4290 if (poped) {
4291 ADD_INSN(ret, nd_line(node), pop);
4293 break;
4295 case NODE_CLASS:{
4296 VALUE iseqval =
4297 NEW_CHILD_ISEQVAL(
4298 node->nd_body,
4299 rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4300 ISEQ_TYPE_CLASS);
4301 compile_cpath(ret, iseq, node->nd_cpath);
4302 COMPILE(ret, "super", node->nd_super);
4303 ADD_INSN3(ret, nd_line(node), defineclass,
4304 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(0));
4306 if (poped) {
4307 ADD_INSN(ret, nd_line(node), pop);
4309 break;
4311 case NODE_MODULE:{
4312 VALUE iseqval = NEW_CHILD_ISEQVAL(
4313 node->nd_body,
4314 rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4315 ISEQ_TYPE_CLASS);
4317 compile_cpath(ret, iseq, node->nd_cpath);
4318 ADD_INSN (ret, nd_line(node), putnil); /* dummy */
4319 ADD_INSN3(ret, nd_line(node), defineclass,
4320 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2));
4321 if (poped) {
4322 ADD_INSN(ret, nd_line(node), pop);
4324 break;
4326 case NODE_SCLASS:{
4327 ID singletonclass;
4328 VALUE iseqval =
4329 NEW_ISEQVAL(node->nd_body, rb_str_new2("singletonclass"),
4330 ISEQ_TYPE_CLASS);
4332 COMPILE(ret, "sclass#recv", node->nd_recv);
4333 ADD_INSN (ret, nd_line(node), putnil);
4334 CONST_ID(singletonclass, "singletonclass");
4335 ADD_INSN3(ret, nd_line(node), defineclass,
4336 ID2SYM(singletonclass), iseqval, INT2FIX(1));
4338 if (poped) {
4339 ADD_INSN(ret, nd_line(node), pop);
4341 break;
4343 case NODE_COLON2:{
4344 if (rb_is_const_id(node->nd_mid)) {
4345 /* constant */
4346 LABEL *lstart = NEW_LABEL(nd_line(node));
4347 LABEL *lend = NEW_LABEL(nd_line(node));
4348 DECL_ANCHOR(pref);
4349 DECL_ANCHOR(body);
4351 INIT_ANCHOR(pref);
4352 INIT_ANCHOR(body);
4353 compile_colon2(iseq, node, pref, body);
4354 if (LIST_SIZE_ZERO(pref)) {
4355 if (iseq->compile_data->option->inline_const_cache) {
4356 ADD_LABEL(ret, lstart);
4357 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4359 else {
4360 ADD_INSN(ret, nd_line(node), putnil);
4363 ADD_SEQ(ret, body);
4365 if (iseq->compile_data->option->inline_const_cache) {
4366 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4367 ADD_LABEL(ret, lend);
4370 else {
4371 ADD_SEQ(ret, pref);
4372 ADD_SEQ(ret, body);
4375 else {
4376 /* function call */
4377 ADD_CALL_RECEIVER(ret, nd_line(node));
4378 COMPILE(ret, "colon2#nd_head", node->nd_head);
4379 ADD_CALL(ret, nd_line(node), ID2SYM(node->nd_mid),
4380 INT2FIX(1));
4382 if (poped) {
4383 ADD_INSN(ret, nd_line(node), pop);
4385 break;
4387 case NODE_COLON3:{
4388 LABEL *lstart = NEW_LABEL(nd_line(node));
4389 LABEL *lend = NEW_LABEL(nd_line(node));
4390 debugi("colon3#nd_mid", node->nd_mid);
4392 /* add cache insn */
4393 if (iseq->compile_data->option->inline_const_cache) {
4394 ADD_LABEL(ret, lstart);
4395 ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend);
4396 ADD_INSN(ret, nd_line(node), pop);
4399 ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
4400 ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4402 if (iseq->compile_data->option->inline_const_cache) {
4403 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4404 ADD_LABEL(ret, lend);
4407 if (poped) {
4408 ADD_INSN(ret, nd_line(node), pop);
4410 break;
4412 case NODE_DOT2:
4413 case NODE_DOT3:{
4414 int flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
4415 COMPILE(ret, "min", (NODE *) node->nd_beg);
4416 COMPILE(ret, "max", (NODE *) node->nd_end);
4417 if (poped) {
4418 ADD_INSN(ret, nd_line(node), pop);
4419 ADD_INSN(ret, nd_line(node), pop);
4421 else {
4422 ADD_INSN1(ret, nd_line(node), newrange, flag);
4424 break;
4426 case NODE_FLIP2:
4427 case NODE_FLIP3:{
4428 LABEL *lend = NEW_LABEL(nd_line(node));
4429 LABEL *lfin = NEW_LABEL(nd_line(node));
4430 LABEL *ltrue = NEW_LABEL(nd_line(node));
4431 VALUE key = rb_sprintf("flipflag/%s-%p-%d",
4432 RSTRING_PTR(iseq->name), iseq,
4433 iseq->compile_data->flip_cnt++);
4435 iseq_add_mark_object_compile_time(iseq, key);
4436 ADD_INSN2(ret, nd_line(node), getspecial, key, INT2FIX(0));
4437 ADD_INSNL(ret, nd_line(node), branchif, lend);
4439 /* *flip == 0 */
4440 COMPILE(ret, "flip2 beg", node->nd_beg);
4441 ADD_INSN(ret, nd_line(node), dup);
4442 ADD_INSNL(ret, nd_line(node), branchunless, lfin);
4443 if (nd_type(node) == NODE_FLIP3) {
4444 ADD_INSN(ret, nd_line(node), dup);
4445 ADD_INSN1(ret, nd_line(node), setspecial, key);
4446 ADD_INSNL(ret, nd_line(node), jump, lfin);
4448 else {
4449 ADD_INSN1(ret, nd_line(node), setspecial, key);
4452 /* *flip == 1 */
4453 ADD_LABEL(ret, lend);
4454 COMPILE(ret, "flip2 end", node->nd_end);
4455 ADD_INSNL(ret, nd_line(node), branchunless, ltrue);
4456 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4457 ADD_INSN1(ret, nd_line(node), setspecial, key);
4459 ADD_LABEL(ret, ltrue);
4460 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4462 ADD_LABEL(ret, lfin);
4463 break;
4465 case NODE_SELF:{
4466 if (!poped) {
4467 ADD_INSN(ret, nd_line(node), putself);
4469 break;
4471 case NODE_NIL:{
4472 if (!poped) {
4473 ADD_INSN(ret, nd_line(node), putnil);
4475 break;
4477 case NODE_TRUE:{
4478 if (!poped) {
4479 ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
4481 break;
4483 case NODE_FALSE:{
4484 if (!poped) {
4485 ADD_INSN1(ret, nd_line(node), putobject, Qfalse);
4487 break;
4489 case NODE_ERRINFO:{
4490 if (!poped) {
4491 if (iseq->type == ISEQ_TYPE_RESCUE) {
4492 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
4494 else {
4495 rb_iseq_t *ip = iseq;
4496 int level = 0;
4497 while (ip) {
4498 if (ip->type == ISEQ_TYPE_RESCUE) {
4499 break;
4501 ip = ip->parent_iseq;
4502 level++;
4504 if (ip) {
4505 ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(level));
4507 else {
4508 ADD_INSN(ret, nd_line(node), putnil);
4512 break;
4514 case NODE_DEFINED:{
4515 if (!poped) {
4516 LABEL *lfinish[2];
4517 lfinish[0] = NEW_LABEL(nd_line(node));
4518 lfinish[1] = 0;
4519 defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
4520 if (lfinish[1]) {
4521 ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
4522 ADD_LABEL(ret, lfinish[1]);
4523 ADD_INSN(ret, nd_line(node), putnil);
4525 ADD_LABEL(ret, lfinish[0]);
4527 break;
4529 case NODE_POSTEXE:{
4530 LABEL *lstart = NEW_LABEL(nd_line(node));
4531 LABEL *lend = NEW_LABEL(nd_line(node));
4532 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4534 ADD_LABEL(ret, lstart);
4535 ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend);
4536 ADD_INSN(ret, nd_line(node), pop);
4538 ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4539 ADD_INSN1(ret, nd_line(node), putiseq, block);
4540 ADD_SEND (ret, nd_line(node), ID2SYM(id_core_set_postexe), INT2FIX(1));
4542 ADD_INSN1(ret, nd_line(node), setinlinecache, lstart);
4543 ADD_LABEL(ret, lend);
4545 if (poped) {
4546 ADD_INSN(ret, nd_line(node), pop);
4548 break;
4550 case NODE_DSYM:{
4551 compile_dstr(iseq, ret, node);
4552 if (!poped) {
4553 ADD_SEND(ret, nd_line(node), ID2SYM(idIntern), INT2FIX(0));
4555 else {
4556 ADD_INSN(ret, nd_line(node), pop);
4558 break;
4560 case NODE_ATTRASGN:{
4561 DECL_ANCHOR(recv);
4562 DECL_ANCHOR(args);
4563 unsigned long flag = 0;
4564 VALUE argc;
4566 INIT_ANCHOR(recv);
4567 INIT_ANCHOR(args);
4568 argc = setup_args(iseq, args, node->nd_args, &flag);
4570 if (node->nd_recv == (NODE *) 1) {
4571 flag |= VM_CALL_FCALL_BIT;
4572 ADD_INSN(recv, nd_line(node), putself);
4574 else {
4575 COMPILE(recv, "recv", node->nd_recv);
4578 debugp_param("argc", argc);
4579 debugp_param("nd_mid", ID2SYM(node->nd_mid));
4581 if (!poped) {
4582 ADD_INSN(ret, nd_line(node), putnil);
4583 ADD_SEQ(ret, recv);
4584 ADD_SEQ(ret, args);
4586 if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
4587 ADD_INSN1(ret, nd_line(node), topn, INT2FIX(1));
4588 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 3));
4589 ADD_INSN (ret, nd_line(node), pop);
4591 else {
4592 ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 1));
4595 else {
4596 ADD_SEQ(ret, recv);
4597 ADD_SEQ(ret, args);
4599 ADD_SEND_R(ret, nd_line(node), ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
4600 ADD_INSN(ret, nd_line(node), pop);
4602 break;
4604 case NODE_OPTBLOCK:{
4605 /* for optimize */
4606 LABEL *redo_label = NEW_LABEL(0);
4607 LABEL *next_label = NEW_LABEL(0);
4609 iseq->compile_data->start_label = next_label;
4610 iseq->compile_data->redo_label = redo_label;
4612 ADD_LABEL(ret, redo_label);
4613 COMPILE_(ret, "optblock body", node->nd_head, 1 /* pop */ );
4614 ADD_LABEL(ret, next_label);
4615 ADD_INSN(ret, 0, opt_checkenv);
4616 break;
4618 case NODE_PRELUDE:{
4619 COMPILE_POPED(ret, "prelude", node->nd_head);
4620 COMPILE_(ret, "body", node->nd_body, poped);
4621 break;
4623 case NODE_LAMBDA:{
4624 /* compile same as lambda{...} */
4625 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK);
4626 VALUE argc = INT2FIX(0);
4627 ADD_CALL_RECEIVER(ret, nd_line(node));
4628 ADD_CALL_WITH_BLOCK(ret, nd_line(node), ID2SYM(idLambda), argc, block);
4630 if (poped) {
4631 ADD_INSN(ret, nd_line(node), pop);
4633 break;
4635 default:
4636 rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
4637 return Qnil;
4640 debug_node_end();
4641 return COMPILE_OK;
4644 /***************************/
4645 /* instruction information */
4646 /***************************/
4648 static int
4649 insn_data_length(INSN *iobj)
4651 return insn_len(iobj->insn_id);
4654 static int
4655 calc_sp_depth(int depth, INSN *insn)
4657 return insn_stack_increase(depth, insn->insn_id, insn->operands);
4660 static int
4661 insn_data_line_no(INSN *iobj)
4663 return insn_len(iobj->line_no);
4666 static VALUE
4667 insn_data_to_s_detail(INSN *iobj)
4669 VALUE str = rb_str_new(0, 0);
4671 str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
4672 if (iobj->operands) {
4673 const char *types = insn_op_types(iobj->insn_id);
4674 int j;
4676 for (j = 0; types[j]; j++) {
4677 char type = types[j];
4679 switch (type) {
4680 case TS_OFFSET: /* label(destination position) */
4682 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
4683 rb_str_catf(str, "<L%03d>", lobj->label_no);
4684 break;
4686 break;
4687 case TS_ISEQ: /* iseq */
4689 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
4690 VALUE val = Qnil;
4691 if (iseq) {
4692 val = iseq->self;
4694 rb_str_concat(str, rb_inspect(val));
4696 break;
4697 case TS_LINDEX:
4698 case TS_DINDEX:
4699 case TS_NUM: /* ulong */
4700 case TS_VALUE: /* VALUE */
4701 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4702 break;
4703 case TS_ID: /* ID */
4704 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
4705 break;
4706 case TS_GENTRY:
4708 struct global_entry *entry = (struct global_entry *)
4709 (OPERAND_AT(iobj, j) & (~1));
4710 rb_str_cat2(str, rb_id2name(entry->id));
4712 case TS_IC: /* method cache */
4713 rb_str_cat2(str, "<ic>");
4714 break;
4715 case TS_CDHASH: /* case/when condition cache */
4716 rb_str_cat2(str, "<ch>");
4717 break;
4718 default:{
4719 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
4722 if (types[j + 1]) {
4723 rb_str_cat2(str, ", ");
4727 return str;
4730 static void
4731 dump_disasm_list(struct iseq_link_element *link)
4733 int pos = 0;
4734 INSN *iobj;
4735 LABEL *lobj;
4736 VALUE str;
4738 printf("-- raw disasm--------\n");
4740 while (link) {
4741 switch (link->type) {
4742 case ISEQ_ELEMENT_INSN:
4744 iobj = (INSN *)link;
4745 str = insn_data_to_s_detail(iobj);
4746 printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str),
4747 insn_data_line_no(iobj));
4748 pos += insn_data_length(iobj);
4749 break;
4751 case ISEQ_ELEMENT_LABEL:
4753 lobj = (LABEL *)link;
4754 printf("<L%03d>\n", lobj->label_no);
4755 break;
4757 case ISEQ_ELEMENT_NONE:
4759 printf("[none]\n");
4760 break;
4762 case ISEQ_ELEMENT_ADJUST:
4764 ADJUST *adjust = (ADJUST *)link;
4765 printf("adjust: [label: %d]\n", adjust->label->label_no);
4766 break;
4768 default:
4769 /* ignore */
4770 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
4772 link = link->next;
4774 printf("---------------------\n");
4777 VALUE
4778 insns_name_array(void)
4780 VALUE ary = rb_ary_new();
4781 int i;
4782 for (i = 0; i < sizeof(insn_name_info) / sizeof(insn_name_info[0]); i++) {
4783 rb_ary_push(ary, rb_str_new2(insn_name_info[i]));
4785 return ary;
4788 static LABEL *
4789 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
4791 LABEL *label = 0;
4792 st_data_t tmp;
4793 obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
4795 if (st_lookup(labels_table, obj, &tmp) == 0) {
4796 label = NEW_LABEL(0);
4797 st_insert(labels_table, obj, (st_data_t)label);
4799 else {
4800 label = (LABEL *)tmp;
4802 return label;
4805 static VALUE
4806 get_exception_sym2type(VALUE sym)
4808 #undef rb_intern
4809 static VALUE symRescue, symEnsure, symRetry;
4810 static VALUE symBreak, symRedo, symNext;
4812 if (symRescue == 0) {
4813 symRescue = ID2SYM(rb_intern("rescue"));
4814 symEnsure = ID2SYM(rb_intern("ensure"));
4815 symRetry = ID2SYM(rb_intern("retry"));
4816 symBreak = ID2SYM(rb_intern("break"));
4817 symRedo = ID2SYM(rb_intern("redo"));
4818 symNext = ID2SYM(rb_intern("next"));
4821 if (sym == symRescue) return CATCH_TYPE_RESCUE;
4822 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
4823 if (sym == symRetry) return CATCH_TYPE_RETRY;
4824 if (sym == symBreak) return CATCH_TYPE_BREAK;
4825 if (sym == symRedo) return CATCH_TYPE_REDO;
4826 if (sym == symNext) return CATCH_TYPE_NEXT;
4827 rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
4828 RSTRING_PTR(rb_inspect(sym)));
4829 return 0;
4832 static int
4833 iseq_build_exception(rb_iseq_t *iseq, struct st_table *labels_table,
4834 VALUE exception)
4836 int i;
4838 for (i=0; i<RARRAY_LEN(exception); i++) {
4839 VALUE v, type, *ptr, eiseqval;
4840 LABEL *lstart, *lend, *lcont;
4841 int sp;
4843 RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
4844 "Array", "to_ary");
4845 if (RARRAY_LEN(v) != 6) {
4846 rb_raise(rb_eSyntaxError, "wrong exception entry");
4848 ptr = RARRAY_PTR(v);
4849 type = get_exception_sym2type(ptr[0]);
4850 if (ptr[1] == Qnil) {
4851 eiseqval = 0;
4853 else {
4854 eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil);
4857 lstart = register_label(iseq, labels_table, ptr[2]);
4858 lend = register_label(iseq, labels_table, ptr[3]);
4859 lcont = register_label(iseq, labels_table, ptr[4]);
4860 sp = NUM2INT(ptr[5]);
4862 ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
4864 return COMPILE_OK;
4867 struct st_table *insn_make_insn_table(void);
4869 static int
4870 iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
4871 VALUE body, struct st_table *labels_table)
4873 /* TODO: body should be freezed */
4874 VALUE *ptr = RARRAY_PTR(body);
4875 int len = RARRAY_LEN(body);
4876 int i, j;
4877 int line_no = 0;
4879 * index -> LABEL *label
4881 static struct st_table *insn_table;
4883 if (insn_table == 0) {
4884 insn_table = insn_make_insn_table();
4887 for (i=0; i<len; i++) {
4888 VALUE obj = ptr[i];
4890 if (SYMBOL_P(obj)) {
4891 LABEL *label = register_label(iseq, labels_table, obj);
4892 ADD_LABEL(anchor, label);
4894 else if (FIXNUM_P(obj)) {
4895 line_no = NUM2INT(obj);
4897 else if (TYPE(obj) == T_ARRAY) {
4898 VALUE *argv = 0;
4899 int argc = RARRAY_LEN(obj) - 1;
4900 VALUE insn_id;
4901 VALUE insn;
4903 insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
4904 if (st_lookup(insn_table, insn, &insn_id) == 0) {
4905 /* TODO: exception */
4906 RB_GC_GUARD(insn) = rb_inspect(insn);
4907 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4908 "unknown instruction: %s", RSTRING_PTR(insn));
4911 if (argc != insn_len(insn_id)-1) {
4912 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
4913 "operand size mismatch");
4916 if (argc > 0) {
4917 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
4918 for (j=0; j<argc; j++) {
4919 VALUE op = rb_ary_entry(obj, j+1);
4920 switch (insn_op_type(insn_id, j)) {
4921 case TS_OFFSET: {
4922 LABEL *label = register_label(iseq, labels_table, op);
4923 argv[j] = (VALUE)label;
4924 break;
4926 case TS_LINDEX:
4927 case TS_DINDEX:
4928 case TS_NUM:
4929 argv[j] = (NUM2INT(op), op);
4930 break;
4931 case TS_VALUE:
4932 argv[j] = op;
4933 iseq_add_mark_object(iseq, op);
4934 break;
4935 case TS_ISEQ:
4937 if (op != Qnil) {
4938 if (TYPE(op) == T_ARRAY) {
4939 argv[j] = iseq_load(0, op, iseq->self, Qnil);
4941 else if (CLASS_OF(op) == rb_cISeq) {
4942 argv[j] = op;
4944 else {
4945 rb_raise(rb_eSyntaxError, "ISEQ is required");
4947 iseq_add_mark_object(iseq, argv[j]);
4949 else {
4950 argv[j] = 0;
4953 break;
4954 case TS_GENTRY:
4955 op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
4956 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
4957 break;
4958 case TS_IC:
4959 argv[j] = (VALUE)NEW_INLINE_CACHE_ENTRY();
4960 iseq_add_mark_object(iseq, argv[j]);
4961 break;
4962 case TS_ID:
4963 argv[j] = rb_convert_type(op, T_SYMBOL,
4964 "Symbol", "to_sym");
4965 break;
4966 case TS_CDHASH:
4968 int i;
4969 op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
4970 op = rb_ary_dup(op);
4971 for (i=0; i<RARRAY_LEN(op); i+=2) {
4972 VALUE sym = rb_ary_entry(op, i+1);
4973 LABEL *label =
4974 register_label(iseq, labels_table, sym);
4975 rb_ary_store(op, i+1, (VALUE)label | 1);
4977 argv[j] = op;
4979 break;
4980 default:
4981 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type(insn_id, j));
4985 ADD_ELEM(anchor,
4986 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
4987 insn_id, argc, argv));
4989 else {
4990 rb_raise(rb_eTypeError, "unexpected object for instruction");
4993 st_free_table(labels_table);
4994 iseq_setup(iseq, anchor);
4995 return COMPILE_OK;
4998 #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
4999 #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
5000 #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
5001 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
5003 VALUE
5004 iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
5005 VALUE exception, VALUE body)
5007 int i;
5008 ID *tbl;
5009 struct st_table *labels_table = st_init_numtable();
5011 DECL_ANCHOR(anchor);
5013 INIT_ANCHOR(anchor);
5015 iseq->local_table_size = RARRAY_LEN(locals);
5016 iseq->local_table = tbl = (ID *)ALLOC_N(ID *, iseq->local_table_size);
5017 iseq->local_size = iseq->local_table_size + 1;
5019 for (i=0; i<RARRAY_LEN(locals); i++) {
5020 VALUE lv = RARRAY_PTR(locals)[i];
5021 tbl[i] = FIXNUM_P(lv) ? FIX2INT(lv) : SYM2ID(CHECK_SYMBOL(lv));
5024 /* args */
5025 if (FIXNUM_P(args)) {
5026 iseq->arg_size = iseq->argc = FIX2INT(args);
5027 iseq->arg_simple = 1;
5029 else {
5030 int i = 0;
5031 VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
5032 VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
5033 VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
5034 VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
5035 VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
5036 VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
5037 VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
5039 iseq->argc = FIX2INT(argc);
5040 iseq->arg_rest = FIX2INT(arg_rest);
5041 iseq->arg_post_len = FIX2INT(arg_post_len);
5042 iseq->arg_post_start = FIX2INT(arg_post_start);
5043 iseq->arg_block = FIX2INT(arg_block);
5044 iseq->arg_opts = RARRAY_LEN(arg_opt_labels);
5045 iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
5047 if (iseq->arg_block != -1) {
5048 iseq->arg_size = iseq->arg_block + 1;
5050 else if (iseq->arg_post_len) {
5051 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
5053 else if (iseq->arg_rest != -1) {
5054 iseq->arg_size = iseq->arg_rest + 1;
5056 else {
5057 iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
5060 for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
5061 iseq->arg_opt_table[i] =
5062 (VALUE)register_label(iseq, labels_table,
5063 rb_ary_entry(arg_opt_labels, i));
5066 iseq->arg_simple = NUM2INT(arg_simple);
5069 /* exception */
5070 iseq_build_exception(iseq, labels_table, exception);
5072 /* body */
5073 iseq_build_body(iseq, anchor, body, labels_table);
5074 return iseq->self;