1/**********************************************************************
2
3  compile.c - ruby node tree -> VM instruction sequence
4
5  $Author: nagachika $
6  created at: 04/01/01 03:42:15 JST
7
8  Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/ruby.h"
13#include "internal.h"
14#include <math.h>
15
16#define USE_INSN_STACK_INCREASE 1
17#include "vm_core.h"
18#include "iseq.h"
19#include "insns.inc"
20#include "insns_info.inc"
21
22#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
23#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
24#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
25
26typedef struct iseq_link_element {
27    enum {
28	ISEQ_ELEMENT_NONE,
29	ISEQ_ELEMENT_LABEL,
30	ISEQ_ELEMENT_INSN,
31	ISEQ_ELEMENT_ADJUST
32    } type;
33    struct iseq_link_element *next;
34    struct iseq_link_element *prev;
35} LINK_ELEMENT;
36
37typedef struct iseq_link_anchor {
38    LINK_ELEMENT anchor;
39    LINK_ELEMENT *last;
40} LINK_ANCHOR;
41
42typedef struct iseq_label_data {
43    LINK_ELEMENT link;
44    int label_no;
45    int position;
46    int sc_state;
47    int set;
48    int sp;
49} LABEL;
50
51typedef struct iseq_insn_data {
52    LINK_ELEMENT link;
53    enum ruby_vminsn_type insn_id;
54    unsigned int line_no;
55    int operand_size;
56    int sc_state;
57    VALUE *operands;
58} INSN;
59
60typedef struct iseq_adjust_data {
61    LINK_ELEMENT link;
62    LABEL *label;
63    int line_no;
64} ADJUST;
65
66struct ensure_range {
67    LABEL *begin;
68    LABEL *end;
69    struct ensure_range *next;
70};
71
72struct iseq_compile_data_ensure_node_stack {
73    NODE *ensure_node;
74    struct iseq_compile_data_ensure_node_stack *prev;
75    struct ensure_range *erange;
76};
77
78/**
79 * debug function(macro) interface depend on CPDEBUG
80 * if it is less than 0, runtime option is in effect.
81 *
82 * debug level:
83 *  0: no debug output
84 *  1: show node type
85 *  2: show node important parameters
86 *  ...
87 *  5: show other parameters
88 * 10: show every AST array
89 */
90
91#ifndef CPDEBUG
92#define CPDEBUG 0
93#endif
94
95#if CPDEBUG >= 0
96#define compile_debug CPDEBUG
97#else
98#define compile_debug iseq->compile_data->option->debug_level
99#endif
100
101#if CPDEBUG
102
103#define compile_debug_print_indent(level) \
104    ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
105
106#define debugp(header, value) (void) \
107  (compile_debug_print_indent(1) && \
108   ruby_debug_print_value(1, compile_debug, (header), (value)))
109
110#define debugi(header, id)  (void) \
111  (compile_debug_print_indent(1) && \
112   ruby_debug_print_id(1, compile_debug, (header), (id)))
113
114#define debugp_param(header, value)  (void) \
115  (compile_debug_print_indent(1) && \
116   ruby_debug_print_value(1, compile_debug, (header), (value)))
117
118#define debugp_verbose(header, value)  (void) \
119  (compile_debug_print_indent(2) && \
120   ruby_debug_print_value(2, compile_debug, (header), (value)))
121
122#define debugp_verbose_node(header, value)  (void) \
123  (compile_debug_print_indent(10) && \
124   ruby_debug_print_value(10, compile_debug, (header), (value)))
125
126#define debug_node_start(node)  ((void) \
127  (compile_debug_print_indent(1) && \
128   (ruby_debug_print_node(1, CPDEBUG, "", (NODE *)(node)), gl_node_level)), \
129   gl_node_level++)
130
131#define debug_node_end()  gl_node_level --
132
133#else
134
135static inline ID
136r_id(ID id)
137{
138    return id;
139}
140
141static inline VALUE
142r_value(VALUE value)
143{
144    return value;
145}
146
147#define debugi(header, id)                 r_id(id)
148#define debugp(header, value)              r_value(value)
149#define debugp_verbose(header, value)      r_value(value)
150#define debugp_verbose_node(header, value) r_value(value)
151#define debugp_param(header, value)        r_value(value)
152#define debug_node_start(node)             ((void)0)
153#define debug_node_end()                   ((void)0)
154#endif
155
156#if CPDEBUG > 1 || CPDEBUG < 0
157#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
158#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
159#else
160#define debugs                             if(0)printf
161#define debug_compile(msg, v) (v)
162#endif
163
164
165/* create new label */
166#define NEW_LABEL(l) new_label_body(iseq, (l))
167
168#define iseq_path(iseq) \
169  (((rb_iseq_t*)DATA_PTR(iseq))->location.path)
170
171#define iseq_absolute_path(iseq) \
172  (((rb_iseq_t*)DATA_PTR(iseq))->location.absolute_path)
173
174#define NEW_ISEQVAL(node, name, type, line_no)       \
175  new_child_iseq(iseq, (node), (name), 0, (type), (line_no))
176
177#define NEW_CHILD_ISEQVAL(node, name, type, line_no)       \
178  new_child_iseq(iseq, (node), (name), iseq->self, (type), (line_no))
179
180/* add instructions */
181#define ADD_SEQ(seq1, seq2) \
182  APPEND_LIST((seq1), (seq2))
183
184/* add an instruction */
185#define ADD_INSN(seq, line, insn) \
186  ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
187
188/* add an instruction with some operands (1, 2, 3, 5) */
189#define ADD_INSN1(seq, line, insn, op1) \
190  ADD_ELEM((seq), (LINK_ELEMENT *) \
191           new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
192
193/* add an instruction with label operand (alias of ADD_INSN1) */
194#define ADD_INSNL(seq, line, insn, label) ADD_INSN1(seq, line, insn, label)
195
196#define ADD_INSN2(seq, line, insn, op1, op2) \
197  ADD_ELEM((seq), (LINK_ELEMENT *) \
198           new_insn_body(iseq, (line), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
199
200#define ADD_INSN3(seq, line, insn, op1, op2, op3) \
201  ADD_ELEM((seq), (LINK_ELEMENT *) \
202           new_insn_body(iseq, (line), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
203
204/* Specific Insn factory */
205#define ADD_SEND(seq, line, id, argc) \
206  ADD_SEND_R((seq), (line), (id), (argc), (VALUE)Qfalse, (VALUE)INT2FIX(0))
207
208#define ADD_CALL_RECEIVER(seq, line) \
209  ADD_INSN((seq), (line), putself)
210
211#define ADD_CALL(seq, line, id, argc) \
212  ADD_SEND_R((seq), (line), (id), (argc), (VALUE)Qfalse, (VALUE)INT2FIX(VM_CALL_FCALL))
213
214#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block) \
215  ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL))
216
217#define ADD_SEND_R(seq, line, id, argc, block, flag) \
218  ADD_ELEM((seq), (LINK_ELEMENT *) \
219           new_insn_send(iseq, (line), \
220                         (VALUE)(id), (VALUE)(argc), (VALUE)(block), (VALUE)(flag)))
221
222#define ADD_TRACE(seq, line, event) \
223  do { \
224      if ((event) == RUBY_EVENT_LINE && iseq->coverage && \
225	  (line) != iseq->compile_data->last_coverable_line) { \
226	  RARRAY_PTR(iseq->coverage)[(line) - 1] = INT2FIX(0); \
227	  iseq->compile_data->last_coverable_line = (line); \
228	  ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_COVERAGE)); \
229      } \
230      if (iseq->compile_data->option->trace_instruction) { \
231	  ADD_INSN1((seq), (line), trace, INT2FIX(event)); \
232      } \
233  } while (0)
234
235/* add label */
236#define ADD_LABEL(seq, label) \
237  ADD_ELEM((seq), (LINK_ELEMENT *) (label))
238
239#define APPEND_LABEL(seq, before, label) \
240  APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
241
242#define ADD_ADJUST(seq, line, label) \
243  ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line)))
244
245#define ADD_ADJUST_RESTORE(seq, label) \
246  ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
247
248#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)		\
249    (rb_ary_push(iseq->compile_data->catch_table_ary,		\
250		 rb_ary_new3(5, (type),				\
251			     (VALUE)(ls) | 1, (VALUE)(le) | 1,	\
252			     (VALUE)(iseqv), (VALUE)(lc) | 1)))
253
254/* compile node */
255#define COMPILE(anchor, desc, node) \
256  (debug_compile("== " desc "\n", \
257                 iseq_compile_each(iseq, (anchor), (node), 0)))
258
259/* compile node, this node's value will be popped */
260#define COMPILE_POPED(anchor, desc, node)    \
261  (debug_compile("== " desc "\n", \
262                 iseq_compile_each(iseq, (anchor), (node), 1)))
263
264/* compile node, which is popped when 'poped' is true */
265#define COMPILE_(anchor, desc, node, poped)  \
266  (debug_compile("== " desc "\n", \
267                 iseq_compile_each(iseq, (anchor), (node), (poped))))
268
269#define OPERAND_AT(insn, idx) \
270  (((INSN*)(insn))->operands[(idx)])
271
272#define INSN_OF(insn) \
273  (((INSN*)(insn))->insn_id)
274
275/* error */
276#define COMPILE_ERROR(strs)                        \
277{                                                  \
278  VALUE tmp = GET_THREAD()->errinfo;               \
279  if (compile_debug) rb_compile_bug strs;          \
280  GET_THREAD()->errinfo = iseq->compile_data->err_info;  \
281  rb_compile_error strs;                           \
282  iseq->compile_data->err_info = GET_THREAD()->errinfo; \
283  GET_THREAD()->errinfo = tmp;                     \
284  ret = 0;                                         \
285  break;                                           \
286}
287
288#define ERROR_ARGS ruby_sourcefile, nd_line(node),
289
290
291#define COMPILE_OK 1
292#define COMPILE_NG 0
293
294
295/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
296 * missing */
297#define DECL_ANCHOR(name) \
298  LINK_ANCHOR *name, name##_body__ = {{0,},}
299#define INIT_ANCHOR(name) \
300  (name##_body__.last = &name##_body__.anchor, name = &name##_body__)
301
302#define hide_obj(obj) do {OBJ_FREEZE(obj); RBASIC(obj)->klass = 0;} while (0)
303
304#include "optinsn.inc"
305#if OPT_INSTRUCTIONS_UNIFICATION
306#include "optunifs.inc"
307#endif
308
309/* for debug */
310#if CPDEBUG < 0
311#define ISEQ_ARG iseq,
312#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
313#else
314#define ISEQ_ARG
315#define ISEQ_ARG_DECLARE
316#endif
317
318#if CPDEBUG
319#define gl_node_level iseq->compile_data->node_level
320#if 0
321static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor);
322#endif
323#endif
324
325static void dump_disasm_list(LINK_ELEMENT *elem);
326
327static int insn_data_length(INSN *iobj);
328static int insn_data_line_no(INSN *iobj);
329static int calc_sp_depth(int depth, INSN *iobj);
330
331static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...);
332static LABEL *new_label_body(rb_iseq_t *iseq, long line);
333static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
334
335static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int);
336static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
337static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
338static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
339
340static int iseq_set_local_table(rb_iseq_t *iseq, ID *tbl);
341static int iseq_set_exception_local_table(rb_iseq_t *iseq);
342static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node);
343
344static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
345static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
346static int iseq_set_exception_table(rb_iseq_t *iseq);
347static int iseq_set_optargs_table(rb_iseq_t *iseq);
348
349/*
350 * To make Array to LinkedList, use link_anchor
351 */
352
353static void
354verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *anchor)
355{
356#if CPDEBUG
357    int flag = 0;
358    LINK_ELEMENT *list, *plist;
359
360    if (!compile_debug) return;
361
362    list = anchor->anchor.next;
363    plist = &anchor->anchor;
364    while (list) {
365	if (plist != list->prev) {
366	    flag += 1;
367	}
368	plist = list;
369	list = list->next;
370    }
371
372    if (anchor->last != plist && anchor->last != 0) {
373	flag |= 0x70000;
374    }
375
376    if (flag != 0) {
377	rb_bug("list verify error: %08x (%s)", flag, info);
378    }
379#endif
380}
381#if CPDEBUG < 0
382#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
383#endif
384
385/*
386 * elem1, elem2 => elem1, elem2, elem
387 */
388static void
389ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
390{
391    elem->prev = anchor->last;
392    anchor->last->next = elem;
393    anchor->last = elem;
394    verify_list("add", anchor);
395}
396
397/*
398 * elem1, before, elem2 => elem1, before, elem, elem2
399 */
400static void
401APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
402{
403    elem->prev = before;
404    elem->next = before->next;
405    elem->next->prev = elem;
406    before->next = elem;
407    if (before == anchor->last) anchor->last = elem;
408    verify_list("add", anchor);
409}
410#if CPDEBUG < 0
411#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
412#define APPEND_ELEM(anchor, before, elem) ADD_ELEM(iseq, (anchor), (before), (elem))
413#endif
414
415static int
416iseq_add_mark_object(rb_iseq_t *iseq, VALUE v)
417{
418    if (!SPECIAL_CONST_P(v)) {
419	rb_iseq_add_mark_object(iseq, v);
420    }
421    return COMPILE_OK;
422}
423
424#define ruby_sourcefile		RSTRING_PTR(iseq->location.path)
425
426static int
427iseq_add_mark_object_compile_time(rb_iseq_t *iseq, VALUE v)
428{
429    if (!SPECIAL_CONST_P(v)) {
430	rb_ary_push(iseq->compile_data->mark_ary, v);
431    }
432    return COMPILE_OK;
433}
434
435static int
436validate_label(st_data_t name, st_data_t label, st_data_t arg)
437{
438    rb_iseq_t *iseq = (rb_iseq_t *)arg;
439    LABEL *lobj = (LABEL *)label;
440    if (!lobj->link.next) {
441	do {
442	    int ret;
443	    COMPILE_ERROR((ruby_sourcefile, lobj->position,
444			   "%s: undefined label", rb_id2name((ID)name)));
445	    if (ret) break;
446	} while (0);
447    }
448    return ST_CONTINUE;
449}
450
451static void
452validate_labels(rb_iseq_t *iseq, st_table *labels_table)
453{
454    st_foreach(labels_table, validate_label, (st_data_t)iseq);
455    if (!NIL_P(iseq->compile_data->err_info)) {
456	rb_exc_raise(iseq->compile_data->err_info);
457    }
458}
459
460VALUE
461rb_iseq_compile_node(VALUE self, NODE *node)
462{
463    DECL_ANCHOR(ret);
464    rb_iseq_t *iseq;
465    INIT_ANCHOR(ret);
466    GetISeqPtr(self, iseq);
467
468    if (node == 0) {
469	COMPILE(ret, "nil", node);
470	iseq_set_local_table(iseq, 0);
471    }
472    else if (nd_type(node) == NODE_SCOPE) {
473	/* iseq type of top, method, class, block */
474	iseq_set_local_table(iseq, node->nd_tbl);
475	iseq_set_arguments(iseq, ret, node->nd_args);
476
477	switch (iseq->type) {
478	  case ISEQ_TYPE_BLOCK:
479	    {
480		LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
481		LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
482
483		ADD_LABEL(ret, start);
484		ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_B_CALL);
485		COMPILE(ret, "block body", node->nd_body);
486		ADD_LABEL(ret, end);
487		ADD_TRACE(ret, nd_line(node), RUBY_EVENT_B_RETURN);
488
489		/* wide range catch handler must put at last */
490		ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
491		ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
492		break;
493	    }
494	  case ISEQ_TYPE_CLASS:
495	    {
496		ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
497		COMPILE(ret, "scoped node", node->nd_body);
498		ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
499		break;
500	    }
501	  case ISEQ_TYPE_METHOD:
502	    {
503		ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
504		COMPILE(ret, "scoped node", node->nd_body);
505		ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
506		break;
507	    }
508	  default: {
509	    COMPILE(ret, "scoped node", node->nd_body);
510	    break;
511	  }
512	}
513    }
514    else {
515	switch (iseq->type) {
516	  case ISEQ_TYPE_METHOD:
517	  case ISEQ_TYPE_CLASS:
518	  case ISEQ_TYPE_BLOCK:
519	  case ISEQ_TYPE_EVAL:
520	  case ISEQ_TYPE_MAIN:
521	  case ISEQ_TYPE_TOP:
522	    rb_compile_error(ERROR_ARGS "compile/should not be reached: %s:%d",
523			     __FILE__, __LINE__);
524	    break;
525	  case ISEQ_TYPE_RESCUE:
526	    iseq_set_exception_local_table(iseq);
527	    COMPILE(ret, "rescue", node);
528	    break;
529	  case ISEQ_TYPE_ENSURE:
530	    iseq_set_exception_local_table(iseq);
531	    COMPILE_POPED(ret, "ensure", node);
532	    break;
533	  case ISEQ_TYPE_DEFINED_GUARD:
534	    iseq_set_local_table(iseq, 0);
535	    COMPILE(ret, "defined guard", node);
536	    break;
537	  default:
538	    rb_bug("unknown scope");
539	}
540    }
541
542    if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) {
543	ADD_INSN2(ret, 0, getlocal, INT2FIX(2), INT2FIX(0));
544	ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
545    }
546    else {
547	ADD_INSN(ret, iseq->compile_data->last_line, leave);
548    }
549
550#if SUPPORT_JOKE
551    if (iseq->compile_data->labels_table) {
552	validate_labels(iseq, iseq->compile_data->labels_table);
553    }
554#endif
555    return iseq_setup(iseq, ret);
556}
557
558int
559rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
560{
561#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
562    const void * const *table = rb_vm_get_insns_address_table();
563    unsigned long i;
564
565    iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size);
566    MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size);
567
568    for (i = 0; i < iseq->iseq_size; /* */ ) {
569	int insn = (int)iseq->iseq_encoded[i];
570	int len = insn_len(insn);
571	iseq->iseq_encoded[i] = (VALUE)table[insn];
572	i += len;
573    }
574#else
575    iseq->iseq_encoded = iseq->iseq;
576#endif
577    return COMPILE_OK;
578}
579
580/*********************************************/
581/* definition of data structure for compiler */
582/*********************************************/
583
584static void *
585compile_data_alloc(rb_iseq_t *iseq, size_t size)
586{
587    void *ptr = 0;
588    struct iseq_compile_data_storage *storage =
589	iseq->compile_data->storage_current;
590
591    if (storage->pos + size > storage->size) {
592	unsigned long alloc_size = storage->size * 2;
593
594      retry:
595	if (alloc_size < size) {
596	    alloc_size *= 2;
597	    goto retry;
598	}
599	storage->next = (void *)ALLOC_N(char, alloc_size +
600					sizeof(struct
601					       iseq_compile_data_storage));
602	storage = iseq->compile_data->storage_current = storage->next;
603	storage->next = 0;
604	storage->pos = 0;
605	storage->size = alloc_size;
606	storage->buff = (char *)(&storage->buff + 1);
607    }
608
609    ptr = (void *)&storage->buff[storage->pos];
610    storage->pos += size;
611    return ptr;
612}
613
614static INSN *
615compile_data_alloc_insn(rb_iseq_t *iseq)
616{
617    return (INSN *)compile_data_alloc(iseq, sizeof(INSN));
618}
619
620static LABEL *
621compile_data_alloc_label(rb_iseq_t *iseq)
622{
623    return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
624}
625
626static ADJUST *
627compile_data_alloc_adjust(rb_iseq_t *iseq)
628{
629    return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
630}
631
632/*
633 * elem1, elemX => elem1, elem2, elemX
634 */
635static void
636INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
637{
638    elem2->next = elem1->next;
639    elem2->prev = elem1;
640    elem1->next = elem2;
641    if (elem2->next) {
642	elem2->next->prev = elem2;
643    }
644}
645
646#if 0 /* unused */
647/*
648 * elemX, elem1 => elemX, elem2, elem1
649 */
650static void
651INSERT_ELEM_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
652{
653    elem2->prev = elem1->prev;
654    elem2->next = elem1;
655    elem1->prev = elem2;
656    if (elem2->prev) {
657	elem2->prev->next = elem2;
658    }
659}
660#endif
661
662/*
663 * elemX, elem1, elemY => elemX, elem2, elemY
664 */
665static void
666REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
667{
668    elem2->prev = elem1->prev;
669    elem2->next = elem1->next;
670    if (elem1->prev) {
671	elem1->prev->next = elem2;
672    }
673    if (elem1->next) {
674	elem1->next->prev = elem2;
675    }
676}
677
678static void
679REMOVE_ELEM(LINK_ELEMENT *elem)
680{
681    elem->prev->next = elem->next;
682    if (elem->next) {
683	elem->next->prev = elem->prev;
684    }
685}
686
687static LINK_ELEMENT *
688FIRST_ELEMENT(LINK_ANCHOR *anchor)
689{
690    return anchor->anchor.next;
691}
692
693#if 0 /* unused */
694static LINK_ELEMENT *
695LAST_ELEMENT(LINK_ANCHOR *anchor)
696{
697  return anchor->last;
698}
699#endif
700
701static LINK_ELEMENT *
702POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
703{
704    LINK_ELEMENT *elem = anchor->last;
705    anchor->last = anchor->last->prev;
706    anchor->last->next = 0;
707    verify_list("pop", anchor);
708    return elem;
709}
710#if CPDEBUG < 0
711#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
712#endif
713
714#if 0 /* unused */
715static LINK_ELEMENT *
716SHIFT_ELEMENT(LINK_ANCHOR *anchor)
717{
718    LINK_ELEMENT *elem = anchor->anchor.next;
719    if (elem) {
720	anchor->anchor.next = elem->next;
721    }
722    return elem;
723}
724#endif
725
726#if 0 /* unused */
727static int
728LIST_SIZE(LINK_ANCHOR *anchor)
729{
730    LINK_ELEMENT *elem = anchor->anchor.next;
731    int size = 0;
732    while (elem) {
733	size += 1;
734	elem = elem->next;
735    }
736    return size;
737}
738#endif
739
740static int
741LIST_SIZE_ZERO(LINK_ANCHOR *anchor)
742{
743    if (anchor->anchor.next == 0) {
744	return 1;
745    }
746    else {
747	return 0;
748    }
749}
750
751/*
752 * anc1: e1, e2, e3
753 * anc2: e4, e5
754 *#=>
755 * anc1: e1, e2, e3, e4, e5
756 * anc2: e4, e5 (broken)
757 */
758static void
759APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
760{
761    if (anc2->anchor.next) {
762	anc1->last->next = anc2->anchor.next;
763	anc2->anchor.next->prev = anc1->last;
764	anc1->last = anc2->last;
765    }
766    verify_list("append", anc1);
767}
768#if CPDEBUG < 0
769#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
770#endif
771
772/*
773 * anc1: e1, e2, e3
774 * anc2: e4, e5
775 *#=>
776 * anc1: e4, e5, e1, e2, e3
777 * anc2: e4, e5 (broken)
778 */
779static void
780INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
781{
782    if (anc2->anchor.next) {
783	LINK_ELEMENT *first = anc1->anchor.next;
784	anc1->anchor.next = anc2->anchor.next;
785	anc1->anchor.next->prev = &anc1->anchor;
786	anc2->last->next = first;
787	if (first) {
788	    first->prev = anc2->last;
789	}
790	else {
791	    anc1->last = anc2->last;
792	}
793    }
794
795    verify_list("append", anc1);
796}
797#if CPDEBUG < 0
798#define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, (anc1), (anc2))
799#endif
800
801#if 0 /* unused */
802/*
803 * anc1: e1, e2, e3
804 * anc2: e4, e5
805 *#=>
806 * anc1: e4, e5
807 * anc2: e1, e2, e3
808 */
809static void
810SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
811{
812    LINK_ANCHOR tmp = *anc2;
813
814    /* it has bug */
815    *anc2 = *anc1;
816    *anc1 = tmp;
817
818    verify_list("swap1", anc1);
819    verify_list("swap2", anc2);
820}
821#if CPDEBUG < 0
822#define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, (anc1), (anc2))
823#endif
824
825static LINK_ANCHOR *
826REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc)
827{
828    LINK_ELEMENT *first, *last, *elem, *e;
829    first = &anc->anchor;
830    elem = first->next;
831    last = anc->last;
832
833    if (elem != 0) {
834	anc->anchor.next = last;
835	anc->last = elem;
836    }
837    else {
838	/* null list */
839	return anc;
840    }
841    while (elem) {
842	e = elem->next;
843	elem->next = elem->prev;
844	elem->prev = e;
845	elem = e;
846    }
847
848    first->next = last;
849    last->prev = first;
850    anc->last->next = 0;
851
852    verify_list("reverse", anc);
853    return anc;
854}
855#if CPDEBUG < 0
856#define REVERSE_LIST(anc) REVERSE_LIST(iseq, (anc))
857#endif
858#endif
859
860#if CPDEBUG && 0
861static void
862debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
863{
864    LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
865    printf("----\n");
866    printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
867	   anchor->anchor.next, anchor->last);
868    while (list) {
869	printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
870	       list->prev, FIX2INT(list->type));
871	list = list->next;
872    }
873    printf("----\n");
874
875    dump_disasm_list(anchor->anchor.next);
876    verify_list("debug list", anchor);
877}
878#if CPDEBUG < 0
879#define debug_list(anc) debug_list(iseq, (anc))
880#endif
881#endif
882
883static LABEL *
884new_label_body(rb_iseq_t *iseq, long line)
885{
886    LABEL *labelobj = compile_data_alloc_label(iseq);
887
888    labelobj->link.type = ISEQ_ELEMENT_LABEL;
889    labelobj->link.next = 0;
890
891    labelobj->label_no = iseq->compile_data->label_no++;
892    labelobj->sc_state = 0;
893    labelobj->sp = -1;
894    return labelobj;
895}
896
897static ADJUST *
898new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
899{
900    ADJUST *adjust = compile_data_alloc_adjust(iseq);
901    adjust->link.type = ISEQ_ELEMENT_ADJUST;
902    adjust->link.next = 0;
903    adjust->label = label;
904    adjust->line_no = line;
905    return adjust;
906}
907
908static INSN *
909new_insn_core(rb_iseq_t *iseq, int line_no,
910	      int insn_id, int argc, VALUE *argv)
911{
912    INSN *iobj = compile_data_alloc_insn(iseq);
913    /* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
914
915    iobj->link.type = ISEQ_ELEMENT_INSN;
916    iobj->link.next = 0;
917    iobj->insn_id = insn_id;
918    iobj->line_no = line_no;
919    iobj->operands = argv;
920    iobj->operand_size = argc;
921    iobj->sc_state = 0;
922    return iobj;
923}
924
925static INSN *
926new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...)
927{
928    VALUE *operands = 0;
929    va_list argv;
930    if (argc > 0) {
931	int i;
932	va_init_list(argv, argc);
933	operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
934	for (i = 0; i < argc; i++) {
935	    VALUE v = va_arg(argv, VALUE);
936	    operands[i] = v;
937	}
938	va_end(argv);
939    }
940    return new_insn_core(iseq, line_no, insn_id, argc, operands);
941}
942
943static rb_call_info_t *
944new_callinfo(rb_iseq_t *iseq, ID mid, int argc, VALUE block, unsigned long flag)
945{
946    rb_call_info_t *ci = (rb_call_info_t *)compile_data_alloc(iseq, sizeof(rb_call_info_t));
947    ci->mid = mid;
948    ci->flag = flag;
949    ci->orig_argc = argc;
950    ci->argc = argc;
951
952    if (block) {
953	GetISeqPtr(block, ci->blockiseq);
954    }
955    else {
956	ci->blockiseq = 0;
957	if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG))) {
958	    ci->flag |= VM_CALL_ARGS_SKIP_SETUP;
959	}
960    }
961    ci->vmstat = 0;
962    ci->blockptr = 0;
963    ci->recv = Qundef;
964    ci->call = 0; /* TODO: should set default function? */
965
966    ci->aux.index = iseq->callinfo_size++;
967
968    return ci;
969}
970
971static INSN *
972new_insn_send(rb_iseq_t *iseq, int line_no, VALUE id, VALUE argc, VALUE block, VALUE flag)
973{
974    VALUE *operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 1);
975    operands[0] = (VALUE)new_callinfo(iseq, SYM2ID(id), FIX2INT(argc), block, FIX2INT(flag));
976    return new_insn_core(iseq, line_no, BIN(send), 1, operands);
977}
978
979static VALUE
980new_child_iseq(rb_iseq_t *iseq, NODE *node,
981	       VALUE name, VALUE parent, enum iseq_type type, int line_no)
982{
983    VALUE ret;
984
985    debugs("[new_child_iseq]> ---------------------------------------\n");
986    ret = rb_iseq_new_with_opt(node, name,
987			       iseq_path(iseq->self), iseq_absolute_path(iseq->self),
988			       INT2FIX(line_no), parent, type, iseq->compile_data->option);
989    debugs("[new_child_iseq]< ---------------------------------------\n");
990    iseq_add_mark_object(iseq, ret);
991    return ret;
992}
993
994static int
995iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
996{
997    /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
998
999    if (compile_debug > 5)
1000	dump_disasm_list(FIRST_ELEMENT(anchor));
1001
1002    debugs("[compile step 3.1 (iseq_optimize)]\n");
1003    iseq_optimize(iseq, anchor);
1004
1005    if (compile_debug > 5)
1006	dump_disasm_list(FIRST_ELEMENT(anchor));
1007
1008    if (iseq->compile_data->option->instructions_unification) {
1009	debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1010	iseq_insns_unification(iseq, anchor);
1011	if (compile_debug > 5)
1012	    dump_disasm_list(FIRST_ELEMENT(anchor));
1013    }
1014
1015    if (iseq->compile_data->option->stack_caching) {
1016	debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1017	iseq_set_sequence_stackcaching(iseq, anchor);
1018	if (compile_debug > 5)
1019	    dump_disasm_list(FIRST_ELEMENT(anchor));
1020    }
1021
1022    debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1023    iseq_set_sequence(iseq, anchor);
1024    if (compile_debug > 5)
1025	dump_disasm_list(FIRST_ELEMENT(anchor));
1026
1027    debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1028    iseq_set_exception_table(iseq);
1029
1030    debugs("[compile step 4.3 (set_optargs_table)] \n");
1031    iseq_set_optargs_table(iseq);
1032
1033    debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1034    rb_iseq_translate_threaded_code(iseq);
1035
1036    if (compile_debug > 1) {
1037	VALUE str = rb_iseq_disasm(iseq->self);
1038	printf("%s\n", StringValueCStr(str));
1039	fflush(stdout);
1040    }
1041    debugs("[compile step: finish]\n");
1042
1043    return 0;
1044}
1045
1046static int
1047iseq_set_exception_local_table(rb_iseq_t *iseq)
1048{
1049    ID id_dollar_bang;
1050
1051    CONST_ID(id_dollar_bang, "#$!");
1052    iseq->local_table = (ID *)ALLOC_N(ID, 1);
1053    iseq->local_table_size = 1;
1054    iseq->local_size = iseq->local_table_size + 1;
1055    iseq->local_table[0] = id_dollar_bang;
1056    return COMPILE_OK;
1057}
1058
1059static int
1060get_lvar_level(rb_iseq_t *iseq)
1061{
1062    int lev = 0;
1063    while (iseq != iseq->local_iseq) {
1064	lev++;
1065	iseq = iseq->parent_iseq;
1066    }
1067    return lev;
1068}
1069
1070static int
1071get_dyna_var_idx_at_raw(rb_iseq_t *iseq, ID id)
1072{
1073    int i;
1074
1075    for (i = 0; i < iseq->local_table_size; i++) {
1076	if (iseq->local_table[i] == id) {
1077	    return i;
1078	}
1079    }
1080    return -1;
1081}
1082
1083static int
1084get_local_var_idx(rb_iseq_t *iseq, ID id)
1085{
1086    int idx = get_dyna_var_idx_at_raw(iseq->local_iseq, id);
1087
1088    if (idx < 0) {
1089	rb_bug("get_local_var_idx: %d", idx);
1090    }
1091
1092    return idx;
1093}
1094
1095static int
1096get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls)
1097{
1098    int lv = 0, idx = -1;
1099
1100    while (iseq) {
1101	idx = get_dyna_var_idx_at_raw(iseq, id);
1102	if (idx >= 0) {
1103	    break;
1104	}
1105	iseq = iseq->parent_iseq;
1106	lv++;
1107    }
1108
1109    if (idx < 0) {
1110	rb_bug("get_dyna_var_idx: -1");
1111    }
1112
1113    *level = lv;
1114    *ls = iseq->local_size;
1115    return idx;
1116}
1117
1118static int
1119iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
1120{
1121    debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1122
1123    if (node_args) {
1124	struct rb_args_info *args = node_args->nd_ainfo;
1125	ID rest_id = 0;
1126	int last_comma = 0;
1127	ID block_id = 0;
1128
1129	if (nd_type(node_args) != NODE_ARGS) {
1130	    rb_bug("iseq_set_arguments: NODE_ARGS is expected, but %s",
1131		   ruby_node_name(nd_type(node_args)));
1132	}
1133
1134
1135	iseq->argc = (int)args->pre_args_num;
1136	debugs("  - argc: %d\n", iseq->argc);
1137
1138	rest_id = args->rest_arg;
1139	if (rest_id == 1) {
1140	    last_comma = 1;
1141	    rest_id = 0;
1142	}
1143	block_id = args->block_arg;
1144
1145	if (args->first_post_arg) {
1146	    iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg);
1147	    iseq->arg_post_len = args->post_args_num;
1148	}
1149
1150	if (args->opt_args) {
1151	    NODE *node = args->opt_args;
1152	    LABEL *label;
1153	    VALUE labels = rb_ary_tmp_new(1);
1154	    int i = 0, j;
1155
1156	    while (node) {
1157		label = NEW_LABEL(nd_line(node));
1158		rb_ary_push(labels, (VALUE)label | 1);
1159		ADD_LABEL(optargs, label);
1160		COMPILE_POPED(optargs, "optarg", node->nd_body);
1161		node = node->nd_next;
1162		i += 1;
1163	    }
1164
1165	    /* last label */
1166	    label = NEW_LABEL(nd_line(node_args));
1167	    rb_ary_push(labels, (VALUE)label | 1);
1168	    ADD_LABEL(optargs, label);
1169	    i += 1;
1170
1171	    iseq->arg_opts = i;
1172	    iseq->arg_opt_table = ALLOC_N(VALUE, i);
1173	    MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i);
1174	    for (j = 0; j < i; j++) {
1175		iseq->arg_opt_table[j] &= ~1;
1176	    }
1177	    rb_ary_clear(labels);
1178	}
1179	else {
1180	    iseq->arg_opts = 0;
1181	}
1182
1183	if (args->kw_args) {
1184	    NODE *node = args->kw_args;
1185	    VALUE keywords = rb_ary_tmp_new(1);
1186	    int i = 0, j;
1187
1188	    iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
1189	    COMPILE(optargs, "kwarg", args->kw_rest_arg);
1190	    while (node) {
1191		rb_ary_push(keywords, INT2FIX(node->nd_body->nd_vid));
1192		COMPILE_POPED(optargs, "kwarg", node); /* nd_type(node) == NODE_KW_ARG */
1193		node = node->nd_next;
1194		i += 1;
1195	    }
1196	    iseq->arg_keyword_check = (args->kw_rest_arg->nd_vid & ID_SCOPE_MASK) == ID_JUNK;
1197	    iseq->arg_keywords = i;
1198	    iseq->arg_keyword_table = ALLOC_N(ID, i);
1199	    for (j = 0; j < i; j++) {
1200		iseq->arg_keyword_table[j] = FIX2INT(RARRAY_PTR(keywords)[j]);
1201	    }
1202	    ADD_INSN(optargs, nd_line(args->kw_args), pop);
1203	}
1204	else if (args->kw_rest_arg) {
1205	    iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
1206	    COMPILE(optargs, "kwarg", args->kw_rest_arg);
1207	    ADD_INSN(optargs, nd_line(args->kw_rest_arg), pop);
1208	}
1209	else {
1210	    iseq->arg_keyword = -1;
1211	}
1212
1213	if (args->pre_init) { /* m_init */
1214	    COMPILE_POPED(optargs, "init arguments (m)", args->pre_init);
1215	}
1216	if (args->post_init) { /* p_init */
1217	    COMPILE_POPED(optargs, "init arguments (p)", args->post_init);
1218	}
1219
1220	if (rest_id) {
1221	    iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id);
1222
1223	    if (iseq->arg_rest == -1) {
1224		rb_bug("arg_rest: -1");
1225	    }
1226
1227	    if (iseq->arg_post_start == 0) {
1228		iseq->arg_post_start = iseq->arg_rest + 1;
1229	    }
1230	}
1231
1232	if (block_id) {
1233	    iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id);
1234	}
1235
1236	if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 ||
1237	    iseq->arg_rest != -1 || iseq->arg_block != -1 ||
1238	    iseq->arg_keyword != -1) {
1239	    iseq->arg_simple = 0;
1240
1241	    /* set arg_size: size of arguments */
1242	    if (iseq->arg_keyword != -1) {
1243		iseq->arg_size = iseq->arg_keyword + 1;
1244	    }
1245	    else if (iseq->arg_block != -1) {
1246		iseq->arg_size = iseq->arg_block + 1;
1247	    }
1248	    else if (iseq->arg_post_len) {
1249		iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
1250	    }
1251	    else if (iseq->arg_rest != -1) {
1252		iseq->arg_size = iseq->arg_rest + 1;
1253	    }
1254	    else if (iseq->arg_opts) {
1255		iseq->arg_size = iseq->argc + iseq->arg_opts - 1;
1256	    }
1257	    else {
1258		iseq->arg_size = iseq->argc;
1259	    }
1260	}
1261	else {
1262	    iseq->arg_simple = 1;
1263	    iseq->arg_size = iseq->argc;
1264	}
1265
1266	if (iseq->type == ISEQ_TYPE_BLOCK) {
1267	    if (iseq->arg_opts == 0 && iseq->arg_post_len == 0 &&
1268		iseq->arg_rest == -1 && iseq->arg_keyword == -1) {
1269		if (iseq->argc == 1 && last_comma == 0) {
1270		    /* {|a|} */
1271		    iseq->arg_simple |= 0x02;
1272		}
1273	    }
1274	}
1275    }
1276    else {
1277	iseq->arg_simple = 1;
1278    }
1279
1280    return COMPILE_OK;
1281}
1282
1283static int
1284iseq_set_local_table(rb_iseq_t *iseq, ID *tbl)
1285{
1286    int size;
1287
1288    if (tbl) {
1289	size = (int)*tbl;
1290	tbl++;
1291    }
1292    else {
1293	size = 0;
1294    }
1295
1296    if (size > 0) {
1297	iseq->local_table = (ID *)ALLOC_N(ID, size);
1298	MEMCPY(iseq->local_table, tbl, ID, size);
1299    }
1300
1301    iseq->local_size = iseq->local_table_size = size;
1302    iseq->local_size += 1;
1303    /*
1304      if (lfp == dfp ) { // top, class, method
1305	  dfp[-1]: svar
1306      else {             // block
1307          dfp[-1]: cref
1308      }
1309     */
1310
1311    debugs("iseq_set_local_table: %d, %d\n", iseq->local_size, iseq->local_table_size);
1312    return COMPILE_OK;
1313}
1314
1315static int
1316cdhash_cmp(VALUE val, VALUE lit)
1317{
1318    if (val == lit) return 0;
1319    if (SPECIAL_CONST_P(lit)) {
1320	return val != lit;
1321    }
1322    if (SPECIAL_CONST_P(val) || BUILTIN_TYPE(val) != BUILTIN_TYPE(lit)) {
1323	return -1;
1324    }
1325    if (BUILTIN_TYPE(lit) == T_STRING) {
1326	return rb_str_hash_cmp(lit, val);
1327    }
1328    return !rb_eql(lit, val);
1329}
1330
1331static st_index_t
1332cdhash_hash(VALUE a)
1333{
1334    if (SPECIAL_CONST_P(a)) return (st_index_t)a;
1335    if (RB_TYPE_P(a, T_STRING)) return rb_str_hash(a);
1336    {
1337	VALUE hval = rb_hash(a);
1338	return (st_index_t)FIX2LONG(hval);
1339    }
1340}
1341
1342static const struct st_hash_type cdhash_type = {
1343    cdhash_cmp,
1344    cdhash_hash,
1345};
1346
1347struct cdhash_set_label_struct {
1348    VALUE hash;
1349    int pos;
1350    int len;
1351};
1352
1353static int
1354cdhash_set_label_i(VALUE key, VALUE val, void *ptr)
1355{
1356    struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
1357    LABEL *lobj = (LABEL *)(val & ~1);
1358    rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
1359    return ST_CONTINUE;
1360}
1361
1362/**
1363  ruby insn object list -> raw instruction sequence
1364 */
1365static int
1366iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1367{
1368    LABEL *lobj;
1369    INSN *iobj;
1370    struct iseq_line_info_entry *line_info_table;
1371    unsigned int last_line = 0;
1372    LINK_ELEMENT *list;
1373    VALUE *generated_iseq;
1374
1375    int k, pos, sp, stack_max = 0, line = 0;
1376
1377    /* set label position */
1378    list = FIRST_ELEMENT(anchor);
1379    k = pos = 0;
1380    while (list) {
1381	switch (list->type) {
1382	  case ISEQ_ELEMENT_INSN:
1383	    {
1384		iobj = (INSN *)list;
1385		line = iobj->line_no;
1386		pos += insn_data_length(iobj);
1387		k++;
1388		break;
1389	    }
1390	  case ISEQ_ELEMENT_LABEL:
1391	    {
1392		lobj = (LABEL *)list;
1393		lobj->position = pos;
1394		lobj->set = TRUE;
1395		break;
1396	    }
1397	  case ISEQ_ELEMENT_NONE:
1398	    {
1399		/* ignore */
1400		break;
1401	    }
1402	  case ISEQ_ELEMENT_ADJUST:
1403	    {
1404		ADJUST *adjust = (ADJUST *)list;
1405		if (adjust->line_no != -1) {
1406		    pos += 2 /* insn + 1 operand */;
1407		    k++;
1408		}
1409		break;
1410	    }
1411	  default:
1412	    dump_disasm_list(FIRST_ELEMENT(anchor));
1413	    dump_disasm_list(list);
1414	    rb_compile_error(RSTRING_PTR(iseq->location.path), line,
1415			     "error: set_sequence");
1416	    break;
1417	}
1418	list = list->next;
1419    }
1420
1421    /* make instruction sequence */
1422    generated_iseq = ALLOC_N(VALUE, pos);
1423    line_info_table = ALLOC_N(struct iseq_line_info_entry, k);
1424    iseq->ic_entries = ALLOC_N(struct iseq_inline_cache_entry, iseq->ic_size);
1425    MEMZERO(iseq->ic_entries, struct iseq_inline_cache_entry, iseq->ic_size);
1426    iseq->callinfo_entries = ALLOC_N(rb_call_info_t, iseq->callinfo_size);
1427    /* MEMZERO(iseq->callinfo_entries, rb_call_info_t, iseq->callinfo_size); */
1428
1429    list = FIRST_ELEMENT(anchor);
1430    k = pos = sp = 0;
1431
1432    while (list) {
1433	switch (list->type) {
1434	  case ISEQ_ELEMENT_INSN:
1435	    {
1436		int j, len, insn;
1437		const char *types;
1438		VALUE *operands;
1439
1440		iobj = (INSN *)list;
1441
1442		/* update sp */
1443		sp = calc_sp_depth(sp, iobj);
1444		if (sp > stack_max) {
1445		    stack_max = sp;
1446		}
1447
1448		/* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
1449		operands = iobj->operands;
1450		insn = iobj->insn_id;
1451		generated_iseq[pos] = insn;
1452		types = insn_op_types(insn);
1453		len = insn_len(insn);
1454
1455		/* operand check */
1456		if (iobj->operand_size != len - 1) {
1457		    /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
1458		    dump_disasm_list(list);
1459		    rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
1460				     "operand size miss! (%d for %d)",
1461				     iobj->operand_size, len - 1);
1462		    xfree(generated_iseq);
1463		    xfree(line_info_table);
1464		    return 0;
1465		}
1466
1467		for (j = 0; types[j]; j++) {
1468		    char type = types[j];
1469		    /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
1470		    switch (type) {
1471		      case TS_OFFSET:
1472			{
1473			    /* label(destination position) */
1474			    lobj = (LABEL *)operands[j];
1475			    if (!lobj->set) {
1476				rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
1477						 "unknown label");
1478			    }
1479			    if (lobj->sp == -1) {
1480				lobj->sp = sp;
1481			    }
1482			    generated_iseq[pos + 1 + j] = lobj->position - (pos + len);
1483			    break;
1484			}
1485		      case TS_CDHASH:
1486			{
1487			    VALUE map = operands[j];
1488			    struct cdhash_set_label_struct data;
1489                            data.hash = map;
1490                            data.pos = pos;
1491                            data.len = len;
1492			    rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
1493
1494			    hide_obj(map);
1495			    generated_iseq[pos + 1 + j] = map;
1496			    break;
1497			}
1498		      case TS_LINDEX:
1499		      case TS_NUM:	/* ulong */
1500			generated_iseq[pos + 1 + j] = FIX2INT(operands[j]);
1501			break;
1502		      case TS_ISEQ:	/* iseq */
1503			{
1504			    VALUE v = operands[j];
1505			    rb_iseq_t *block = 0;
1506			    if (v) {
1507				GetISeqPtr(v, block);
1508			    }
1509			    generated_iseq[pos + 1 + j] = (VALUE)block;
1510			    break;
1511			}
1512		      case TS_VALUE:	/* VALUE */
1513			{
1514			    VALUE v = operands[j];
1515			    generated_iseq[pos + 1 + j] = v;
1516			    /* to mark ruby object */
1517			    iseq_add_mark_object(iseq, v);
1518			    break;
1519			}
1520		      case TS_IC: /* inline cache */
1521			{
1522			    int ic_index = FIX2INT(operands[j]);
1523			    IC ic = &iseq->ic_entries[ic_index];
1524			    if (UNLIKELY(ic_index >= iseq->ic_size)) {
1525				rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->ic_size);
1526			    }
1527			    generated_iseq[pos + 1 + j] = (VALUE)ic;
1528			    break;
1529			}
1530		      case TS_CALLINFO: /* call info */
1531			{
1532			    rb_call_info_t *base_ci = (rb_call_info_t *)operands[j];
1533			    rb_call_info_t *ci = &iseq->callinfo_entries[base_ci->aux.index];
1534			    *ci = *base_ci;
1535
1536			    if (UNLIKELY(base_ci->aux.index >= iseq->callinfo_size)) {
1537				rb_bug("iseq_set_sequence: ci_index overflow: index: %d, size: %d", base_ci->argc, iseq->callinfo_size);
1538			    }
1539			    generated_iseq[pos + 1 + j] = (VALUE)ci;
1540			    break;
1541			}
1542		      case TS_ID: /* ID */
1543			generated_iseq[pos + 1 + j] = SYM2ID(operands[j]);
1544			break;
1545		      case TS_GENTRY:
1546			{
1547			    struct rb_global_entry *entry =
1548				(struct rb_global_entry *)(operands[j] & (~1));
1549			    generated_iseq[pos + 1 + j] = (VALUE)entry;
1550			}
1551			break;
1552		      default:
1553			rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
1554					 "unknown operand type: %c", type);
1555			xfree(generated_iseq);
1556			xfree(line_info_table);
1557			return 0;
1558		    }
1559		}
1560		if (last_line != iobj->line_no) {
1561		    line_info_table[k].line_no = last_line = iobj->line_no;
1562		    line_info_table[k].position = pos;
1563		    k++;
1564		}
1565		pos += len;
1566		break;
1567	    }
1568	  case ISEQ_ELEMENT_LABEL:
1569	    {
1570		lobj = (LABEL *)list;
1571		if (lobj->sp == -1) {
1572		    lobj->sp = sp;
1573		}
1574		else {
1575		    sp = lobj->sp;
1576		}
1577		break;
1578	    }
1579	  case ISEQ_ELEMENT_ADJUST:
1580	    {
1581		ADJUST *adjust = (ADJUST *)list;
1582		int orig_sp = sp;
1583
1584		if (adjust->label) {
1585		    sp = adjust->label->sp;
1586		}
1587		else {
1588		    sp = 0;
1589		}
1590
1591		if (adjust->line_no != -1) {
1592		    if (orig_sp - sp > 0) {
1593			if (last_line != (unsigned int)adjust->line_no) {
1594			    line_info_table[k].line_no = last_line = adjust->line_no;
1595			    line_info_table[k].position = pos;
1596			    k++;
1597			}
1598			generated_iseq[pos++] = BIN(adjuststack);
1599			generated_iseq[pos++] = orig_sp - sp;
1600		    }
1601		    else if (orig_sp - sp == 0) {
1602			/* jump to next insn */
1603			if (last_line != (unsigned int)adjust->line_no) {
1604			    line_info_table[k].line_no = last_line = adjust->line_no;
1605			    line_info_table[k].position = pos;
1606			    k++;
1607			}
1608			generated_iseq[pos++] = BIN(jump);
1609			generated_iseq[pos++] = 0;
1610		    }
1611		    else {
1612			rb_bug("iseq_set_sequence: adjust bug");
1613		    }
1614		}
1615		break;
1616	    }
1617	  default:
1618	    /* ignore */
1619	    break;
1620	}
1621	list = list->next;
1622    }
1623
1624#if 0 /* XXX */
1625    /* this check need dead code elimination */
1626    if (sp != 1) {
1627	rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
1628    }
1629#endif
1630
1631    iseq->iseq = (void *)generated_iseq;
1632    iseq->iseq_size = pos;
1633    iseq->stack_max = stack_max;
1634
1635    line_info_table = ruby_xrealloc(line_info_table, k * sizeof(struct iseq_line_info_entry));
1636    iseq->line_info_table = line_info_table;
1637    iseq->line_info_size = k;
1638
1639    return COMPILE_OK;
1640}
1641
1642static int
1643label_get_position(LABEL *lobj)
1644{
1645    return lobj->position;
1646}
1647
1648static int
1649label_get_sp(LABEL *lobj)
1650{
1651    return lobj->sp;
1652}
1653
1654static int
1655iseq_set_exception_table(rb_iseq_t *iseq)
1656{
1657    VALUE *tptr, *ptr;
1658    int tlen, i;
1659    struct iseq_catch_table_entry *entry;
1660
1661    tlen = (int)RARRAY_LEN(iseq->compile_data->catch_table_ary);
1662    tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary);
1663
1664    iseq->catch_table = tlen ? ALLOC_N(struct iseq_catch_table_entry, tlen) : 0;
1665    iseq->catch_table_size = tlen;
1666
1667    for (i = 0; i < tlen; i++) {
1668	ptr = RARRAY_PTR(tptr[i]);
1669	entry = &iseq->catch_table[i];
1670	entry->type = (enum catch_type)(ptr[0] & 0xffff);
1671	entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
1672	entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
1673	entry->iseq = ptr[3];
1674
1675	/* register iseq as mark object */
1676	if (entry->iseq != 0) {
1677	    iseq_add_mark_object(iseq, entry->iseq);
1678	}
1679
1680	/* stack depth */
1681	if (ptr[4]) {
1682	    LABEL *lobj = (LABEL *)(ptr[4] & ~1);
1683	    entry->cont = label_get_position(lobj);
1684	    entry->sp = label_get_sp(lobj);
1685
1686	    /* TODO: Dirty Hack!  Fix me */
1687	    if (entry->type == CATCH_TYPE_RESCUE ||
1688		entry->type == CATCH_TYPE_BREAK ||
1689		entry->type == CATCH_TYPE_NEXT) {
1690		entry->sp--;
1691	    }
1692	}
1693	else {
1694	    entry->cont = 0;
1695	}
1696    }
1697
1698    iseq->compile_data->catch_table_ary = 0;	/* free */
1699    return COMPILE_OK;
1700}
1701
1702/*
1703 * set optional argument table
1704 *   def foo(a, b=expr1, c=expr2)
1705 *   =>
1706 *    b:
1707 *      expr1
1708 *    c:
1709 *      expr2
1710 */
1711static int
1712iseq_set_optargs_table(rb_iseq_t *iseq)
1713{
1714    int i;
1715
1716    if (iseq->arg_opts != 0) {
1717	for (i = 0; i < iseq->arg_opts; i++) {
1718	    iseq->arg_opt_table[i] =
1719		label_get_position((LABEL *)iseq->arg_opt_table[i]);
1720	}
1721    }
1722    return COMPILE_OK;
1723}
1724
1725static LINK_ELEMENT *
1726get_destination_insn(INSN *iobj)
1727{
1728    LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
1729    LINK_ELEMENT *list;
1730
1731    list = lobj->link.next;
1732    while (list) {
1733	if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1734	    break;
1735	}
1736	list = list->next;
1737    }
1738    return list;
1739}
1740
1741static LINK_ELEMENT *
1742get_next_insn(INSN *iobj)
1743{
1744    LINK_ELEMENT *list = iobj->link.next;
1745
1746    while (list) {
1747	if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1748	    return list;
1749	}
1750	list = list->next;
1751    }
1752    return 0;
1753}
1754
1755static LINK_ELEMENT *
1756get_prev_insn(INSN *iobj)
1757{
1758    LINK_ELEMENT *list = iobj->link.prev;
1759
1760    while (list) {
1761	if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
1762	    return list;
1763	}
1764	list = list->prev;
1765    }
1766    return 0;
1767}
1768
1769static int
1770iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
1771{
1772    INSN *iobj = (INSN *)list;
1773  again:
1774    if (iobj->insn_id == BIN(jump)) {
1775	INSN *niobj, *diobj, *piobj;
1776	/*
1777	 *  useless jump elimination:
1778	 *     jump LABEL1
1779	 *     ...
1780	 *   LABEL1:
1781	 *     jump LABEL2
1782	 *
1783	 *   => in this case, first jump instruction should jump to
1784	 *      LABEL2 directly
1785	 */
1786	diobj = (INSN *)get_destination_insn(iobj);
1787	niobj = (INSN *)get_next_insn(iobj);
1788
1789	if (diobj == niobj) {
1790	    /*
1791	     *   jump LABEL
1792	     *  LABEL:
1793	     * =>
1794	     *   LABEL:
1795	     */
1796	    REMOVE_ELEM(&iobj->link);
1797	}
1798	else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
1799	    if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
1800		OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0);
1801		goto again;
1802	    }
1803	}
1804	else if (diobj->insn_id == BIN(leave)) {
1805	    /*
1806	     *  jump LABEL
1807	     *  ...
1808	     * LABEL:
1809	     *  leave
1810	     * =>
1811	     *  leave
1812	     *  ...
1813	     * LABEL:
1814	     *  leave
1815	     */
1816	    INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave),
1817					diobj->operand_size, diobj->operands);
1818	    INSN *popiobj = new_insn_core(iseq, iobj->line_no,
1819					  BIN(pop), 0, 0);
1820	    /* replace */
1821	    REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj);
1822	    INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj);
1823	    iobj = popiobj;
1824	}
1825	/*
1826	 * useless jump elimination (if/unless destination):
1827	 *   if   L1
1828	 *   jump L2
1829	 * L1:
1830	 *   ...
1831	 * L2:
1832	 *
1833	 * ==>
1834	 *   unless L2
1835	 * L1:
1836	 *   ...
1837	 * L2:
1838	 */
1839	else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 &&
1840		 (piobj->insn_id == BIN(branchif) ||
1841		  piobj->insn_id == BIN(branchunless))) {
1842	    if (niobj == (INSN *)get_destination_insn(piobj)) {
1843		piobj->insn_id = (piobj->insn_id == BIN(branchif))
1844		  ? BIN(branchunless) : BIN(branchif);
1845		OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0);
1846		REMOVE_ELEM(&iobj->link);
1847	    }
1848	}
1849    }
1850
1851    if (iobj->insn_id == BIN(branchif) ||
1852	iobj->insn_id == BIN(branchunless)) {
1853	/*
1854	 *   if L1
1855	 *   ...
1856	 * L1:
1857	 *   jump L2
1858	 * =>
1859	 *   if L2
1860	 */
1861	INSN *nobj = (INSN *)get_destination_insn(iobj);
1862	if (nobj->insn_id == BIN(jump)) {
1863	    OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
1864	}
1865    }
1866
1867    if (do_tailcallopt && iobj->insn_id == BIN(leave)) {
1868	/*
1869	 *  send ...
1870	 *  leave
1871	 * =>
1872	 *  send ..., ... | VM_CALL_TAILCALL, ...
1873	 *  leave # unreachable
1874	 */
1875	INSN *piobj = (INSN *)get_prev_insn((INSN *)list);
1876
1877	if (piobj->insn_id == BIN(send) || piobj->insn_id == BIN(opt_send_simple)) {
1878	    rb_call_info_t *ci = (rb_call_info_t *)piobj->operands[0];
1879	    if (ci->blockiseq == 0) {
1880		ci->flag |= VM_CALL_TAILCALL;
1881	    }
1882	}
1883    }
1884    return COMPILE_OK;
1885}
1886
1887static int
1888insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
1889{
1890    int old_opsize = iobj->operand_size;
1891    iobj->insn_id = insn_id;
1892    iobj->operand_size = insn_len(insn_id) - 1;
1893
1894    if (iobj->operand_size > old_opsize) {
1895	VALUE *old_operands = iobj->operands;
1896	if (insn_id != BIN(opt_neq)) {
1897	    rb_bug("insn_set_specialized_instruction: unknown insn: %d", insn_id);
1898	}
1899	iobj->operands = (VALUE *)compile_data_alloc(iseq, iobj->operand_size * sizeof(VALUE));
1900	iobj->operands[0] = old_operands[0];
1901	iobj->operands[1] = (VALUE)new_callinfo(iseq, idEq, 1, 0, 0);
1902    }
1903
1904    return COMPILE_OK;
1905}
1906
1907static int
1908iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
1909{
1910    if (iobj->insn_id == BIN(send)) {
1911	rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, 0);
1912
1913#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
1914	if (ci->blockiseq == 0 && (ci->flag & ~VM_CALL_ARGS_SKIP_SETUP) == 0) {
1915	    switch (ci->orig_argc) {
1916	      case 0:
1917		switch (ci->mid) {
1918		  case idLength: SP_INSN(length); return COMPILE_OK;
1919		  case idSize:	 SP_INSN(size);	  return COMPILE_OK;
1920		  case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
1921		  case idSucc:	 SP_INSN(succ);	  return COMPILE_OK;
1922		  case idNot:	 SP_INSN(not);	  return COMPILE_OK;
1923		}
1924		break;
1925	      case 1:
1926		switch (ci->mid) {
1927		  case idPLUS:	 SP_INSN(plus);	  return COMPILE_OK;
1928		  case idMINUS:	 SP_INSN(minus);  return COMPILE_OK;
1929		  case idMULT:	 SP_INSN(mult);	  return COMPILE_OK;
1930		  case idDIV:	 SP_INSN(div);	  return COMPILE_OK;
1931		  case idMOD:	 SP_INSN(mod);	  return COMPILE_OK;
1932		  case idEq:	 SP_INSN(eq);	  return COMPILE_OK;
1933		  case idNeq:	 SP_INSN(neq);	  return COMPILE_OK;
1934		  case idLT:	 SP_INSN(lt);	  return COMPILE_OK;
1935		  case idLE:	 SP_INSN(le);	  return COMPILE_OK;
1936		  case idGT:	 SP_INSN(gt);	  return COMPILE_OK;
1937		  case idGE:	 SP_INSN(ge);	  return COMPILE_OK;
1938		  case idLTLT:	 SP_INSN(ltlt);	  return COMPILE_OK;
1939		  case idAREF:	 SP_INSN(aref);	  return COMPILE_OK;
1940		}
1941		break;
1942	    }
1943	}
1944	if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) {
1945	    iobj->insn_id = BIN(opt_send_simple);
1946	}
1947    }
1948#undef SP_INSN
1949
1950    return COMPILE_OK;
1951}
1952
1953static int
1954iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
1955{
1956    LINK_ELEMENT *list;
1957    const int do_peepholeopt = iseq->compile_data->option->peephole_optimization;
1958    const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization;
1959    const int do_si = iseq->compile_data->option->specialized_instruction;
1960    const int do_ou = iseq->compile_data->option->operands_unification;
1961    list = FIRST_ELEMENT(anchor);
1962
1963    while (list) {
1964	if (list->type == ISEQ_ELEMENT_INSN) {
1965	    if (do_peepholeopt) {
1966		iseq_peephole_optimize(iseq, list, do_tailcallopt);
1967	    }
1968	    if (do_si) {
1969		iseq_specialized_instruction(iseq, (INSN *)list);
1970	    }
1971	    if (do_ou) {
1972		insn_operands_unification((INSN *)list);
1973	    }
1974	}
1975	list = list->next;
1976    }
1977    return COMPILE_OK;
1978}
1979
1980#if OPT_INSTRUCTIONS_UNIFICATION
1981static INSN *
1982new_unified_insn(rb_iseq_t *iseq,
1983		 int insn_id, int size, LINK_ELEMENT *seq_list)
1984{
1985    INSN *iobj = 0;
1986    LINK_ELEMENT *list = seq_list;
1987    int i, argc = 0;
1988    VALUE *operands = 0, *ptr = 0;
1989
1990
1991    /* count argc */
1992    for (i = 0; i < size; i++) {
1993	iobj = (INSN *)list;
1994	argc += iobj->operand_size;
1995	list = list->next;
1996    }
1997
1998    if (argc > 0) {
1999	ptr = operands =
2000	    (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
2001    }
2002
2003    /* copy operands */
2004    list = seq_list;
2005    for (i = 0; i < size; i++) {
2006	iobj = (INSN *)list;
2007	MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
2008	ptr += iobj->operand_size;
2009	list = list->next;
2010    }
2011
2012    return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands);
2013}
2014#endif
2015
2016/*
2017 * This scheme can get more performance if do this optimize with
2018 * label address resolving.
2019 * It's future work (if compile time was bottle neck).
2020 */
2021static int
2022iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
2023{
2024#if OPT_INSTRUCTIONS_UNIFICATION
2025    LINK_ELEMENT *list;
2026    INSN *iobj, *niobj;
2027    int id, k;
2028    intptr_t j;
2029
2030    list = FIRST_ELEMENT(anchor);
2031    while (list) {
2032	if (list->type == ISEQ_ELEMENT_INSN) {
2033	    iobj = (INSN *)list;
2034	    id = iobj->insn_id;
2035	    if (unified_insns_data[id] != 0) {
2036		const int *const *entry = unified_insns_data[id];
2037		for (j = 1; j < (intptr_t)entry[0]; j++) {
2038		    const int *unified = entry[j];
2039		    LINK_ELEMENT *li = list->next;
2040		    for (k = 2; k < unified[1]; k++) {
2041			if (li->type != ISEQ_ELEMENT_INSN ||
2042			    ((INSN *)li)->insn_id != unified[k]) {
2043			    goto miss;
2044			}
2045			li = li->next;
2046		    }
2047		    /* matched */
2048		    niobj =
2049			new_unified_insn(iseq, unified[0], unified[1] - 1,
2050					 list);
2051
2052		    /* insert to list */
2053		    niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
2054		    niobj->link.next = li;
2055		    if (li) {
2056			li->prev = (LINK_ELEMENT *)niobj;
2057		    }
2058
2059		    list->prev->next = (LINK_ELEMENT *)niobj;
2060		    list = (LINK_ELEMENT *)niobj;
2061		    break;
2062		  miss:;
2063		}
2064	    }
2065	}
2066	list = list->next;
2067    }
2068#endif
2069    return COMPILE_OK;
2070}
2071
2072#if OPT_STACK_CACHING
2073
2074#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
2075#define SC_NEXT(insn)       sc_insn_next[(insn)]
2076
2077#include "opt_sc.inc"
2078
2079static int
2080insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state)
2081{
2082    int nstate;
2083    int insn_id;
2084
2085    insn_id = iobj->insn_id;
2086    iobj->insn_id = SC_INSN(insn_id, state);
2087    nstate = SC_NEXT(iobj->insn_id);
2088
2089    if (insn_id == BIN(jump) ||
2090	insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
2091	LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2092
2093	if (lobj->sc_state != 0) {
2094	    if (lobj->sc_state != nstate) {
2095		dump_disasm_list((LINK_ELEMENT *)iobj);
2096		dump_disasm_list((LINK_ELEMENT *)lobj);
2097		printf("\n-- %d, %d\n", lobj->sc_state, nstate);
2098		rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
2099				 "insn_set_sc_state error\n");
2100		return 0;
2101	    }
2102	}
2103	else {
2104	    lobj->sc_state = nstate;
2105	}
2106	if (insn_id == BIN(jump)) {
2107	    nstate = SCS_XX;
2108	}
2109    }
2110    else if (insn_id == BIN(leave)) {
2111	nstate = SCS_XX;
2112    }
2113
2114    return nstate;
2115}
2116
2117static int
2118label_set_sc_state(LABEL *lobj, int state)
2119{
2120    if (lobj->sc_state != 0) {
2121	if (lobj->sc_state != state) {
2122	    state = lobj->sc_state;
2123	}
2124    }
2125    else {
2126	lobj->sc_state = state;
2127    }
2128
2129    return state;
2130}
2131
2132
2133#endif
2134
2135static int
2136iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
2137{
2138#if OPT_STACK_CACHING
2139    LINK_ELEMENT *list;
2140    int state, insn_id;
2141
2142    /* initialize */
2143    state = SCS_XX;
2144    list = FIRST_ELEMENT(anchor);
2145    /* dump_disasm_list(list); */
2146
2147    /* for each list element */
2148    while (list) {
2149      redo_point:
2150	switch (list->type) {
2151	  case ISEQ_ELEMENT_INSN:
2152	    {
2153		INSN *iobj = (INSN *)list;
2154		insn_id = iobj->insn_id;
2155
2156		/* dump_disasm_list(list); */
2157
2158		switch (insn_id) {
2159		  case BIN(nop):
2160		    {
2161			/* exception merge point */
2162			if (state != SCS_AX) {
2163			    INSN *rpobj =
2164				new_insn_body(iseq, 0, BIN(reput), 0);
2165
2166			    /* replace this insn */
2167			    REPLACE_ELEM(list, (LINK_ELEMENT *)rpobj);
2168			    list = (LINK_ELEMENT *)rpobj;
2169			    goto redo_point;
2170			}
2171			break;
2172		    }
2173		  case BIN(swap):
2174		    {
2175			if (state == SCS_AB || state == SCS_BA) {
2176			    state = (state == SCS_AB ? SCS_BA : SCS_AB);
2177
2178			    REMOVE_ELEM(list);
2179			    list = list->next;
2180			    goto redo_point;
2181			}
2182			break;
2183		    }
2184		  case BIN(pop):
2185		    {
2186			switch (state) {
2187			  case SCS_AX:
2188			  case SCS_BX:
2189			    state = SCS_XX;
2190			    break;
2191			  case SCS_AB:
2192			    state = SCS_AX;
2193			    break;
2194			  case SCS_BA:
2195			    state = SCS_BX;
2196			    break;
2197			  case SCS_XX:
2198			    goto normal_insn;
2199			  default:
2200			    rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
2201					     "unreachable");
2202			}
2203			/* remove useless pop */
2204			REMOVE_ELEM(list);
2205			list = list->next;
2206			goto redo_point;
2207		    }
2208		  default:;
2209		    /* none */
2210		}		/* end of switch */
2211	      normal_insn:
2212		state = insn_set_sc_state(iseq, iobj, state);
2213		break;
2214	    }
2215	  case ISEQ_ELEMENT_LABEL:
2216	    {
2217		LABEL *lobj;
2218		lobj = (LABEL *)list;
2219
2220		state = label_set_sc_state(lobj, state);
2221	    }
2222	  default:
2223	    break;
2224	}
2225	list = list->next;
2226    }
2227#endif
2228    return COMPILE_OK;
2229}
2230
2231static int
2232compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int *cntp)
2233{
2234    NODE *list = node->nd_next;
2235    VALUE lit = node->nd_lit;
2236    int cnt = 0;
2237
2238    debugp_param("nd_lit", lit);
2239    if (!NIL_P(lit)) {
2240	hide_obj(lit);
2241	cnt++;
2242	ADD_INSN1(ret, nd_line(node), putobject, lit);
2243    }
2244
2245    while (list) {
2246	node = list->nd_head;
2247	if (nd_type(node) == NODE_STR) {
2248	    hide_obj(node->nd_lit);
2249	    ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
2250	}
2251	else {
2252	    COMPILE(ret, "each string", node);
2253	}
2254	cnt++;
2255	list = list->nd_next;
2256    }
2257    *cntp = cnt;
2258
2259    return COMPILE_OK;
2260}
2261
2262static int
2263compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
2264{
2265    int cnt;
2266    compile_dstr_fragments(iseq, ret, node, &cnt);
2267    ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
2268    return COMPILE_OK;
2269}
2270
2271static int
2272compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
2273{
2274    int cnt;
2275    compile_dstr_fragments(iseq, ret, node, &cnt);
2276    ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
2277    return COMPILE_OK;
2278}
2279
2280static int
2281compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
2282			 LABEL *then_label, LABEL *else_label)
2283{
2284    switch (nd_type(cond)) {
2285      case NODE_AND:
2286	{
2287	    LABEL *label = NEW_LABEL(nd_line(cond));
2288	    compile_branch_condition(iseq, ret, cond->nd_1st, label,
2289				     else_label);
2290	    ADD_LABEL(ret, label);
2291	    compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
2292				     else_label);
2293	    break;
2294	}
2295      case NODE_OR:
2296	{
2297	    LABEL *label = NEW_LABEL(nd_line(cond));
2298	    compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
2299				     label);
2300	    ADD_LABEL(ret, label);
2301	    compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
2302				     else_label);
2303	    break;
2304	}
2305      case NODE_LIT:		/* NODE_LIT is always not true */
2306      case NODE_TRUE:
2307      case NODE_STR:
2308	/* printf("useless condition eliminate (%s)\n",  ruby_node_name(nd_type(cond))); */
2309	ADD_INSNL(ret, nd_line(cond), jump, then_label);
2310	break;
2311      case NODE_FALSE:
2312      case NODE_NIL:
2313	/* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
2314	ADD_INSNL(ret, nd_line(cond), jump, else_label);
2315	break;
2316      default:
2317	COMPILE(ret, "branch condition", cond);
2318	ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
2319	ADD_INSNL(ret, nd_line(cond), jump, then_label);
2320	break;
2321    }
2322    return COMPILE_OK;
2323}
2324
2325enum compile_array_type_t {
2326    COMPILE_ARRAY_TYPE_ARRAY,
2327    COMPILE_ARRAY_TYPE_HASH,
2328    COMPILE_ARRAY_TYPE_ARGS
2329};
2330
2331static int
2332compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
2333	       enum compile_array_type_t type, int poped)
2334{
2335    NODE *node = node_root;
2336    int line = (int)nd_line(node);
2337    int len = 0;
2338
2339    if (nd_type(node) == NODE_ZARRAY) {
2340	if (!poped) {
2341	    switch (type) {
2342	      case COMPILE_ARRAY_TYPE_ARRAY: ADD_INSN1(ret, line, newarray, INT2FIX(0)); break;
2343	      case COMPILE_ARRAY_TYPE_HASH: ADD_INSN1(ret, line, newhash, INT2FIX(0)); break;
2344	      case COMPILE_ARRAY_TYPE_ARGS: /* do nothing */ break;
2345	    }
2346	}
2347    }
2348    else {
2349	int opt_p = 1;
2350	int first = 1, i;
2351
2352	while (node) {
2353	    NODE *start_node = node, *end_node;
2354	    NODE *kw = 0;
2355	    const int max = 0x100;
2356	    DECL_ANCHOR(anchor);
2357	    INIT_ANCHOR(anchor);
2358
2359	    for (i=0; i<max && node; i++, len++, node = node->nd_next) {
2360		if (CPDEBUG > 0 && nd_type(node) != NODE_ARRAY) {
2361		    rb_bug("compile_array: This node is not NODE_ARRAY, but %s", ruby_node_name(nd_type(node)));
2362		}
2363
2364		if (type == COMPILE_ARRAY_TYPE_HASH && !node->nd_head) {
2365		    opt_p = 0;
2366		    kw = node->nd_next;
2367		    node = kw->nd_next;
2368		    kw = kw->nd_head;
2369		    break;
2370		}
2371		if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
2372		    opt_p = 0;
2373		}
2374
2375		COMPILE_(anchor, "array element", node->nd_head, poped);
2376	    }
2377
2378	    if (opt_p && type != COMPILE_ARRAY_TYPE_ARGS) {
2379		if (!poped) {
2380		    VALUE ary = rb_ary_tmp_new(i);
2381
2382		    end_node = node;
2383		    node = start_node;
2384
2385		    while (node != end_node) {
2386			rb_ary_push(ary, node->nd_head->nd_lit);
2387			node = node->nd_next;
2388		    }
2389		    while (node && nd_type(node->nd_head) == NODE_LIT &&
2390			   node->nd_next && nd_type(node->nd_next->nd_head) == NODE_LIT) {
2391			rb_ary_push(ary, node->nd_head->nd_lit);
2392			node = node->nd_next;
2393			rb_ary_push(ary, node->nd_head->nd_lit);
2394			node = node->nd_next;
2395			len++;
2396		    }
2397
2398		    OBJ_FREEZE(ary);
2399
2400		    iseq_add_mark_object_compile_time(iseq, ary);
2401
2402		    if (first) {
2403			first = 0;
2404			if (type == COMPILE_ARRAY_TYPE_ARRAY) {
2405			    ADD_INSN1(ret, line, duparray, ary);
2406			}
2407			else { /* COMPILE_ARRAY_TYPE_HASH */
2408			    ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2409			    ADD_INSN1(ret, line, putobject, ary);
2410			    ADD_SEND(ret, line, ID2SYM(id_core_hash_from_ary), INT2FIX(1));
2411			}
2412		    }
2413		    else {
2414			if (type == COMPILE_ARRAY_TYPE_ARRAY) {
2415			    ADD_INSN1(ret, line, putobject, ary);
2416			    ADD_INSN(ret, line, concatarray);
2417			}
2418			else {
2419			    ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2420			    ADD_INSN1(ret, line, putobject, ary);
2421			    ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ary), INT2FIX(1));
2422			}
2423		    }
2424		}
2425	    }
2426	    else {
2427		if (!poped) {
2428		    switch (type) {
2429		      case COMPILE_ARRAY_TYPE_ARRAY:
2430			ADD_INSN1(anchor, line, newarray, INT2FIX(i));
2431
2432			if (first) {
2433			    first = 0;
2434			}
2435			else {
2436			    ADD_INSN(anchor, line, concatarray);
2437			}
2438
2439			APPEND_LIST(ret, anchor);
2440			break;
2441		      case COMPILE_ARRAY_TYPE_HASH:
2442			if (first) {
2443			    first = 0;
2444			    ADD_INSN1(anchor, line, newhash, INT2FIX(i));
2445			    APPEND_LIST(ret, anchor);
2446			}
2447			else if (i > 0) {
2448			    ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2449			    ADD_INSN(ret, line, swap);
2450			    APPEND_LIST(ret, anchor);
2451			    ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i + 1));
2452			}
2453			if (kw) {
2454			    ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2455			    ADD_INSN(ret, line, swap);
2456			    COMPILE(ret, "keyword splat", kw);
2457			    ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_kwd), INT2FIX(2));
2458			}
2459			break;
2460		      case COMPILE_ARRAY_TYPE_ARGS:
2461			APPEND_LIST(ret, anchor);
2462			break;
2463		    }
2464		}
2465		else {
2466		    /* poped */
2467		    APPEND_LIST(ret, anchor);
2468		}
2469	    }
2470	}
2471    }
2472    return len;
2473}
2474
2475static VALUE
2476compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, enum compile_array_type_t type)
2477{
2478    return compile_array_(iseq, ret, node_root, type, 0);
2479}
2480
2481static VALUE
2482case_when_optimizable_literal(NODE * node)
2483{
2484    switch (nd_type(node)) {
2485      case NODE_LIT: {
2486	VALUE v = node->nd_lit;
2487	double ival;
2488	if (RB_TYPE_P(v, T_FLOAT) &&
2489	    modf(RFLOAT_VALUE(v), &ival) == 0.0) {
2490	    return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
2491	}
2492	if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
2493	    return v;
2494	}
2495	break;
2496      }
2497      case NODE_STR:
2498	return node->nd_lit;
2499    }
2500    return Qundef;
2501}
2502
2503static int
2504when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
2505{
2506    while (vals) {
2507	NODE* val = vals->nd_head;
2508	VALUE lit = case_when_optimizable_literal(val);
2509
2510	if (lit == Qundef) {
2511	    only_special_literals = 0;
2512	}
2513	else {
2514	    if (rb_hash_lookup(literals, lit) != Qnil) {
2515		rb_compile_warning(RSTRING_PTR(iseq->location.path), nd_line(val), "duplicated when clause is ignored");
2516	    }
2517	    else {
2518		rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
2519	    }
2520	}
2521
2522	ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
2523
2524	if (nd_type(val) == NODE_STR) {
2525	    debugp_param("nd_lit", val->nd_lit);
2526	    OBJ_FREEZE(val->nd_lit);
2527	    ADD_INSN1(cond_seq, nd_line(val), putobject, val->nd_lit);
2528	}
2529	else {
2530	    COMPILE(cond_seq, "when cond", val);
2531	}
2532
2533	ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
2534	ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
2535	vals = vals->nd_next;
2536    }
2537    return only_special_literals;
2538}
2539
2540static int
2541compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
2542{
2543    switch (nd_type(node)) {
2544      case NODE_ATTRASGN: {
2545	INSN *iobj;
2546	rb_call_info_t *ci;
2547	VALUE dupidx;
2548
2549	COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node);
2550
2551	POP_ELEMENT(ret);        /* pop pop insn */
2552	iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */
2553	ci = (rb_call_info_t *)iobj->operands[0];
2554	ci->orig_argc += 1; ci->argc = ci->orig_argc;
2555	dupidx = INT2FIX(ci->orig_argc);
2556
2557	ADD_INSN1(ret, nd_line(node), topn, dupidx);
2558	ADD_ELEM(ret, (LINK_ELEMENT *)iobj);
2559	ADD_INSN(ret, nd_line(node), pop);	/* result */
2560	ADD_INSN(ret, nd_line(node), pop);	/* rhs    */
2561	break;
2562      }
2563      case NODE_MASGN: {
2564	DECL_ANCHOR(anchor);
2565	INIT_ANCHOR(anchor);
2566	COMPILE_POPED(anchor, "nest masgn lhs", node);
2567	REMOVE_ELEM(FIRST_ELEMENT(anchor));
2568	ADD_SEQ(ret, anchor);
2569	break;
2570      }
2571      default: {
2572	DECL_ANCHOR(anchor);
2573	INIT_ANCHOR(anchor);
2574	COMPILE_POPED(anchor, "masgn lhs", node);
2575	REMOVE_ELEM(FIRST_ELEMENT(anchor));
2576	ADD_SEQ(ret, anchor);
2577      }
2578    }
2579
2580    return COMPILE_OK;
2581}
2582
2583static void
2584compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn)
2585{
2586    if (lhsn) {
2587	compile_massign_opt_lhs(iseq, ret, lhsn->nd_next);
2588	compile_massign_lhs(iseq, ret, lhsn->nd_head);
2589    }
2590}
2591
2592static int
2593compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2594		    NODE *rhsn, NODE *orig_lhsn)
2595{
2596    VALUE mem[64];
2597    const int memsize = numberof(mem);
2598    int memindex = 0;
2599    int llen = 0, rlen = 0;
2600    int i;
2601    NODE *lhsn = orig_lhsn;
2602
2603#define MEMORY(v) { \
2604    int i; \
2605    if (memindex == memsize) return 0; \
2606    for (i=0; i<memindex; i++) { \
2607	if (mem[i] == (v)) return 0; \
2608    } \
2609    mem[memindex++] = (v); \
2610}
2611
2612    if (rhsn == 0 || nd_type(rhsn) != NODE_ARRAY) {
2613	return 0;
2614    }
2615
2616    while (lhsn) {
2617	NODE *ln = lhsn->nd_head;
2618	switch (nd_type(ln)) {
2619	  case NODE_LASGN:
2620	    MEMORY(ln->nd_vid);
2621	    break;
2622	  case NODE_DASGN:
2623	  case NODE_DASGN_CURR:
2624	  case NODE_IASGN:
2625	  case NODE_IASGN2:
2626	  case NODE_CVASGN:
2627	    MEMORY(ln->nd_vid);
2628	    break;
2629	  default:
2630	    return 0;
2631	}
2632	lhsn = lhsn->nd_next;
2633	llen++;
2634    }
2635
2636    while (rhsn) {
2637	if (llen <= rlen) {
2638	    COMPILE_POPED(ret, "masgn val (popped)", rhsn->nd_head);
2639	}
2640	else {
2641	    COMPILE(ret, "masgn val", rhsn->nd_head);
2642	}
2643	rhsn = rhsn->nd_next;
2644	rlen++;
2645    }
2646
2647    if (llen > rlen) {
2648	for (i=0; i<llen-rlen; i++) {
2649	    ADD_INSN(ret, nd_line(orig_lhsn), putnil);
2650	}
2651    }
2652
2653    compile_massign_opt_lhs(iseq, ret, orig_lhsn);
2654    return 1;
2655}
2656
2657static int
2658compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped)
2659{
2660    NODE *rhsn = node->nd_value;
2661    NODE *splatn = node->nd_args;
2662    NODE *lhsn = node->nd_head;
2663    int lhs_splat = (splatn && (VALUE)splatn != (VALUE)-1) ? 1 : 0;
2664
2665    if (!poped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
2666	int llen = 0;
2667	DECL_ANCHOR(lhsseq);
2668
2669	INIT_ANCHOR(lhsseq);
2670
2671	while (lhsn) {
2672	    compile_massign_lhs(iseq, lhsseq, lhsn->nd_head);
2673	    llen += 1;
2674	    lhsn = lhsn->nd_next;
2675	}
2676
2677	COMPILE(ret, "normal masgn rhs", rhsn);
2678
2679	if (!poped) {
2680	    ADD_INSN(ret, nd_line(node), dup);
2681	}
2682
2683	ADD_INSN2(ret, nd_line(node), expandarray,
2684		  INT2FIX(llen), INT2FIX(lhs_splat));
2685	ADD_SEQ(ret, lhsseq);
2686
2687	if (lhs_splat) {
2688	    if (nd_type(splatn) == NODE_POSTARG) {
2689		/*a, b, *r, p1, p2 */
2690		NODE *postn = splatn->nd_2nd;
2691		NODE *restn = splatn->nd_1st;
2692		int num = (int)postn->nd_alen;
2693		int flag = 0x02 | (((VALUE)restn == (VALUE)-1) ? 0x00 : 0x01);
2694
2695		ADD_INSN2(ret, nd_line(splatn), expandarray,
2696			  INT2FIX(num), INT2FIX(flag));
2697
2698		if ((VALUE)restn != (VALUE)-1) {
2699		    compile_massign_lhs(iseq, ret, restn);
2700		}
2701		while (postn) {
2702		    compile_massign_lhs(iseq, ret, postn->nd_head);
2703		    postn = postn->nd_next;
2704		}
2705	    }
2706	    else {
2707		/* a, b, *r */
2708		compile_massign_lhs(iseq, ret, splatn);
2709	    }
2710	}
2711    }
2712    return COMPILE_OK;
2713}
2714
2715static int
2716compile_colon2(rb_iseq_t *iseq, NODE * node,
2717	       LINK_ANCHOR *pref, LINK_ANCHOR *body)
2718{
2719    switch (nd_type(node)) {
2720      case NODE_CONST:
2721	debugi("compile_colon2 - colon", node->nd_vid);
2722	ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
2723	break;
2724      case NODE_COLON3:
2725	debugi("compile_colon2 - colon3", node->nd_mid);
2726	ADD_INSN(body, nd_line(node), pop);
2727	ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
2728	ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2729	break;
2730      case NODE_COLON2:
2731	compile_colon2(iseq, node->nd_head, pref, body);
2732	debugi("compile_colon2 - colon2", node->nd_mid);
2733	ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
2734	break;
2735      default:
2736	COMPILE(pref, "const colon2 prefix", node);
2737	break;
2738    }
2739    return COMPILE_OK;
2740}
2741
2742static VALUE
2743compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
2744{
2745    if (nd_type(cpath) == NODE_COLON3) {
2746	/* toplevel class ::Foo */
2747	ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
2748	return Qfalse;
2749    }
2750    else if (cpath->nd_head) {
2751	/* Bar::Foo */
2752	COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
2753	return Qfalse;
2754    }
2755    else {
2756	/* class at cbase Foo */
2757	ADD_INSN1(ret, nd_line(cpath), putspecialobject,
2758		  INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
2759	return Qtrue;
2760    }
2761}
2762
2763#define defined_expr defined_expr0
2764static int
2765defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2766	     NODE *node, LABEL **lfinish, VALUE needstr)
2767{
2768    enum defined_type expr_type = 0;
2769    enum node_type type;
2770
2771    switch (type = nd_type(node)) {
2772
2773	/* easy literals */
2774      case NODE_NIL:
2775	expr_type = DEFINED_NIL;
2776	break;
2777      case NODE_SELF:
2778	expr_type = DEFINED_SELF;
2779	break;
2780      case NODE_TRUE:
2781	expr_type = DEFINED_TRUE;
2782	break;
2783      case NODE_FALSE:
2784	expr_type = DEFINED_FALSE;
2785	break;
2786
2787      case NODE_ARRAY:{
2788	NODE *vals = node;
2789
2790	do {
2791	    defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
2792
2793	    if (!lfinish[1]) {
2794		lfinish[1] = NEW_LABEL(nd_line(node));
2795	    }
2796	    ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2797	} while ((vals = vals->nd_next) != NULL);
2798      }
2799      case NODE_STR:
2800      case NODE_LIT:
2801      case NODE_ZARRAY:
2802      case NODE_AND:
2803      case NODE_OR:
2804      default:
2805	expr_type = DEFINED_EXPR;
2806	break;
2807
2808	/* variables */
2809      case NODE_LVAR:
2810      case NODE_DVAR:
2811	expr_type = DEFINED_LVAR;
2812	break;
2813
2814      case NODE_IVAR:
2815	ADD_INSN(ret, nd_line(node), putnil);
2816	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR),
2817		  ID2SYM(node->nd_vid), needstr);
2818	return 1;
2819
2820      case NODE_GVAR:
2821	ADD_INSN(ret, nd_line(node), putnil);
2822	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR),
2823		  ID2SYM(node->nd_entry->id), needstr);
2824	return 1;
2825
2826      case NODE_CVAR:
2827	ADD_INSN(ret, nd_line(node), putnil);
2828	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR),
2829		  ID2SYM(node->nd_vid), needstr);
2830	return 1;
2831
2832      case NODE_CONST:
2833	ADD_INSN(ret, nd_line(node), putnil);
2834	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2835		  ID2SYM(node->nd_vid), needstr);
2836	return 1;
2837      case NODE_COLON2:
2838	if (!lfinish[1]) {
2839	    lfinish[1] = NEW_LABEL(nd_line(node));
2840	}
2841	defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
2842	ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2843
2844	if (rb_is_const_id(node->nd_mid)) {
2845	    COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2846	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
2847		      ID2SYM(node->nd_mid), needstr);
2848	}
2849	else {
2850	    COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
2851	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2852		      ID2SYM(node->nd_mid), needstr);
2853	}
2854	return 1;
2855      case NODE_COLON3:
2856	ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
2857	ADD_INSN3(ret, nd_line(node), defined,
2858		  INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
2859	return 1;
2860
2861	/* method dispatch */
2862      case NODE_CALL:
2863      case NODE_VCALL:
2864      case NODE_FCALL:
2865      case NODE_ATTRASGN:{
2866	int self = TRUE;
2867
2868	switch (type) {
2869	  case NODE_ATTRASGN:
2870	    if (node->nd_recv == (NODE *)1) break;
2871	  case NODE_CALL:
2872	    self = FALSE;
2873	    break;
2874	  default:
2875	    /* through */;
2876	}
2877	if (!lfinish[1]) {
2878	    lfinish[1] = NEW_LABEL(nd_line(node));
2879	}
2880	if (node->nd_args) {
2881	    defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
2882	    ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2883	}
2884	if (!self) {
2885	    defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
2886	    ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
2887	    COMPILE(ret, "defined/recv", node->nd_recv);
2888	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
2889		      ID2SYM(node->nd_mid), needstr);
2890	}
2891	else {
2892	    ADD_INSN(ret, nd_line(node), putself);
2893	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
2894		      ID2SYM(node->nd_mid), needstr);
2895	}
2896	return 1;
2897      }
2898
2899      case NODE_YIELD:
2900	ADD_INSN(ret, nd_line(node), putnil);
2901	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0,
2902		  needstr);
2903	return 1;
2904
2905      case NODE_BACK_REF:
2906      case NODE_NTH_REF:
2907	ADD_INSN(ret, nd_line(node), putnil);
2908	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
2909		  INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
2910		  needstr);
2911	return 1;
2912
2913      case NODE_SUPER:
2914      case NODE_ZSUPER:
2915	ADD_INSN(ret, nd_line(node), putnil);
2916	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
2917		  needstr);
2918	return 1;
2919
2920      case NODE_OP_ASGN1:
2921      case NODE_OP_ASGN2:
2922      case NODE_OP_ASGN_OR:
2923      case NODE_OP_ASGN_AND:
2924      case NODE_MASGN:
2925      case NODE_LASGN:
2926      case NODE_DASGN:
2927      case NODE_DASGN_CURR:
2928      case NODE_GASGN:
2929      case NODE_IASGN:
2930      case NODE_CDECL:
2931      case NODE_CVDECL:
2932      case NODE_CVASGN:
2933	expr_type = DEFINED_ASGN;
2934	break;
2935    }
2936
2937    if (expr_type) {
2938	if (needstr != Qfalse) {
2939	    VALUE str = rb_iseq_defined_string(expr_type);
2940	    ADD_INSN1(ret, nd_line(node), putobject, str);
2941	}
2942	else {
2943	    ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
2944	}
2945	return 1;
2946    }
2947    return 0;
2948}
2949#undef defined_expr
2950
2951static int
2952defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
2953	     NODE *node, LABEL **lfinish, VALUE needstr)
2954{
2955    LINK_ELEMENT *lcur = ret->last;
2956    int done = defined_expr0(iseq, ret, node, lfinish, needstr);
2957    if (lfinish[1]) {
2958	int line = nd_line(node);
2959	LABEL *lstart = NEW_LABEL(line);
2960	LABEL *lend = NEW_LABEL(line);
2961	VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
2962					 rb_str_concat(rb_str_new2
2963						       ("defined guard in "),
2964						       iseq->location.label),
2965					 ISEQ_TYPE_DEFINED_GUARD, 0);
2966	APPEND_LABEL(ret, lcur, lstart);
2967	ADD_LABEL(ret, lend);
2968	ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
2969    }
2970    return done;
2971}
2972
2973#define BUFSIZE 0x100
2974
2975static VALUE
2976make_name_for_block(rb_iseq_t *iseq)
2977{
2978    int level = 1;
2979    rb_iseq_t *ip = iseq;
2980
2981    if (iseq->parent_iseq != 0) {
2982	while (ip->local_iseq != ip) {
2983	    if (ip->type == ISEQ_TYPE_BLOCK) {
2984		level++;
2985	    }
2986	    ip = ip->parent_iseq;
2987	}
2988    }
2989
2990    if (level == 1) {
2991	return rb_sprintf("block in %s", RSTRING_PTR(ip->location.label));
2992    }
2993    else {
2994	return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->location.label));
2995    }
2996}
2997
2998static void
2999push_ensure_entry(rb_iseq_t *iseq,
3000		  struct iseq_compile_data_ensure_node_stack *enl,
3001		  struct ensure_range *er, NODE *node)
3002{
3003    enl->ensure_node = node;
3004    enl->prev = iseq->compile_data->ensure_node_stack;	/* prev */
3005    enl->erange = er;
3006    iseq->compile_data->ensure_node_stack = enl;
3007}
3008
3009static void
3010add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
3011		 LABEL *lstart, LABEL *lend)
3012{
3013    struct ensure_range *ne =
3014	compile_data_alloc(iseq, sizeof(struct ensure_range));
3015
3016    while (erange->next != 0) {
3017	erange = erange->next;
3018    }
3019    ne->next = 0;
3020    ne->begin = lend;
3021    ne->end = erange->end;
3022    erange->end = lstart;
3023
3024    erange->next = ne;
3025}
3026
3027static void
3028add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq, int is_return)
3029{
3030    struct iseq_compile_data_ensure_node_stack *enlp =
3031	iseq->compile_data->ensure_node_stack;
3032    struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
3033    DECL_ANCHOR(ensure);
3034
3035    INIT_ANCHOR(ensure);
3036    while (enlp) {
3037	if (enlp->erange != 0) {
3038	    DECL_ANCHOR(ensure_part);
3039	    LABEL *lstart = NEW_LABEL(0);
3040	    LABEL *lend = NEW_LABEL(0);
3041	    INIT_ANCHOR(ensure_part);
3042
3043	    add_ensure_range(iseq, enlp->erange, lstart, lend);
3044
3045	    iseq->compile_data->ensure_node_stack = enlp->prev;
3046	    ADD_LABEL(ensure_part, lstart);
3047	    COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
3048	    ADD_LABEL(ensure_part, lend);
3049	    ADD_SEQ(ensure, ensure_part);
3050	}
3051	else {
3052	    if (!is_return) {
3053		break;
3054	    }
3055	}
3056	enlp = enlp->prev;
3057    }
3058    iseq->compile_data->ensure_node_stack = prev_enlp;
3059    ADD_SEQ(ret, ensure);
3060}
3061
3062static VALUE
3063setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, VALUE *flag)
3064{
3065    VALUE argc = INT2FIX(0);
3066    int nsplat = 0;
3067    DECL_ANCHOR(arg_block);
3068    DECL_ANCHOR(args_splat);
3069
3070    INIT_ANCHOR(arg_block);
3071    INIT_ANCHOR(args_splat);
3072    if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
3073	COMPILE(arg_block, "block", argn->nd_body);
3074	*flag |= VM_CALL_ARGS_BLOCKARG;
3075	argn = argn->nd_head;
3076    }
3077
3078  setup_argn:
3079    if (argn) {
3080	switch (nd_type(argn)) {
3081	  case NODE_SPLAT: {
3082	    COMPILE(args, "args (splat)", argn->nd_head);
3083	    argc = INT2FIX(1);
3084	    nsplat++;
3085	    *flag |= VM_CALL_ARGS_SPLAT;
3086	    break;
3087	  }
3088	  case NODE_ARGSCAT:
3089	  case NODE_ARGSPUSH: {
3090	    int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
3091	    DECL_ANCHOR(tmp);
3092
3093	    INIT_ANCHOR(tmp);
3094	    COMPILE(tmp, "args (cat: splat)", argn->nd_body);
3095	    if (next_is_array && nsplat == 0) {
3096		/* none */
3097	    }
3098	    else {
3099		if (nd_type(argn) == NODE_ARGSCAT) {
3100		    ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
3101		}
3102		else {
3103		    ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1));
3104		}
3105	    }
3106	    INSERT_LIST(args_splat, tmp);
3107	    nsplat++;
3108	    *flag |= VM_CALL_ARGS_SPLAT;
3109
3110	    if (next_is_array) {
3111		argc = INT2FIX(compile_array(iseq, args, argn->nd_head, COMPILE_ARRAY_TYPE_ARGS) + 1);
3112	    }
3113	    else {
3114		argn = argn->nd_head;
3115		goto setup_argn;
3116	    }
3117	    break;
3118	  }
3119	  case NODE_ARRAY: {
3120	    argc = INT2FIX(compile_array(iseq, args, argn, COMPILE_ARRAY_TYPE_ARGS));
3121	    break;
3122	  }
3123	  default: {
3124	    rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn)));
3125	  }
3126	}
3127    }
3128
3129    if (nsplat > 1) {
3130	int i;
3131	for (i=1; i<nsplat; i++) {
3132	    ADD_INSN(args_splat, nd_line(args), concatarray);
3133	}
3134    }
3135
3136    if (!LIST_SIZE_ZERO(args_splat)) {
3137	ADD_SEQ(args, args_splat);
3138    }
3139
3140    if (*flag & VM_CALL_ARGS_BLOCKARG) {
3141	ADD_SEQ(args, arg_block);
3142    }
3143    return argc;
3144}
3145
3146
3147/**
3148  compile each node
3149
3150  self:  InstructionSequence
3151  node:  Ruby compiled node
3152  poped: This node will be poped
3153 */
3154static int
3155iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
3156{
3157    enum node_type type;
3158    int line;
3159
3160    if (node == 0) {
3161	if (!poped) {
3162	    debugs("node: NODE_NIL(implicit)\n");
3163	    ADD_INSN(ret, iseq->compile_data->last_line, putnil);
3164	}
3165	return COMPILE_OK;
3166    }
3167
3168    iseq->compile_data->last_line = line = (int)nd_line(node);
3169    debug_node_start(node);
3170
3171    type = nd_type(node);
3172
3173    if (node->flags & NODE_FL_NEWLINE) {
3174	ADD_TRACE(ret, line, RUBY_EVENT_LINE);
3175    }
3176
3177    switch (type) {
3178      case NODE_BLOCK:{
3179	while (node && nd_type(node) == NODE_BLOCK) {
3180	    COMPILE_(ret, "BLOCK body", node->nd_head,
3181		     (node->nd_next == 0 && poped == 0) ? 0 : 1);
3182	    node = node->nd_next;
3183	}
3184	if (node) {
3185	    COMPILE_(ret, "BLOCK next", node->nd_next, poped);
3186	}
3187	break;
3188      }
3189      case NODE_IF:{
3190	DECL_ANCHOR(cond_seq);
3191	DECL_ANCHOR(then_seq);
3192	DECL_ANCHOR(else_seq);
3193	LABEL *then_label, *else_label, *end_label;
3194
3195	INIT_ANCHOR(cond_seq);
3196	INIT_ANCHOR(then_seq);
3197	INIT_ANCHOR(else_seq);
3198	then_label = NEW_LABEL(line);
3199	else_label = NEW_LABEL(line);
3200	end_label = NEW_LABEL(line);
3201
3202	compile_branch_condition(iseq, cond_seq, node->nd_cond,
3203				 then_label, else_label);
3204	COMPILE_(then_seq, "then", node->nd_body, poped);
3205	COMPILE_(else_seq, "else", node->nd_else, poped);
3206
3207	ADD_SEQ(ret, cond_seq);
3208
3209	ADD_LABEL(ret, then_label);
3210	ADD_SEQ(ret, then_seq);
3211	ADD_INSNL(ret, line, jump, end_label);
3212
3213	ADD_LABEL(ret, else_label);
3214	ADD_SEQ(ret, else_seq);
3215
3216	ADD_LABEL(ret, end_label);
3217
3218	break;
3219      }
3220      case NODE_CASE:{
3221	NODE *vals;
3222	NODE *tempnode = node;
3223	LABEL *endlabel, *elselabel;
3224	DECL_ANCHOR(head);
3225	DECL_ANCHOR(body_seq);
3226	DECL_ANCHOR(cond_seq);
3227	int only_special_literals = 1;
3228	VALUE literals = rb_hash_new();
3229
3230	INIT_ANCHOR(head);
3231	INIT_ANCHOR(body_seq);
3232	INIT_ANCHOR(cond_seq);
3233
3234	RHASH_TBL(literals)->type = &cdhash_type;
3235
3236	if (node->nd_head == 0) {
3237	    COMPILE_(ret, "when", node->nd_body, poped);
3238	    break;
3239	}
3240	COMPILE(head, "case base", node->nd_head);
3241
3242	node = node->nd_body;
3243	type = nd_type(node);
3244	line = nd_line(node);
3245
3246	if (type != NODE_WHEN) {
3247	    COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
3248	}
3249
3250	endlabel = NEW_LABEL(line);
3251	elselabel = NEW_LABEL(line);
3252
3253	ADD_SEQ(ret, head);	/* case VAL */
3254
3255	while (type == NODE_WHEN) {
3256	    LABEL *l1;
3257
3258	    l1 = NEW_LABEL(line);
3259	    ADD_LABEL(body_seq, l1);
3260	    ADD_INSN(body_seq, line, pop);
3261	    COMPILE_(body_seq, "when body", node->nd_body, poped);
3262	    ADD_INSNL(body_seq, line, jump, endlabel);
3263
3264	    vals = node->nd_head;
3265	    if (vals) {
3266		switch (nd_type(vals)) {
3267		  case NODE_ARRAY:
3268		    only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
3269		    break;
3270		  case NODE_SPLAT:
3271		  case NODE_ARGSCAT:
3272		  case NODE_ARGSPUSH:
3273		    only_special_literals = 0;
3274		    ADD_INSN (cond_seq, nd_line(vals), dup);
3275		    COMPILE(cond_seq, "when/cond splat", vals);
3276		    ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
3277		    ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
3278		    break;
3279		  default:
3280		    rb_bug("NODE_CASE: unknown node (%s)",
3281			   ruby_node_name(nd_type(vals)));
3282		}
3283	    }
3284	    else {
3285		rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
3286	    }
3287
3288	    node = node->nd_next;
3289	    if (!node) {
3290		break;
3291	    }
3292	    type = nd_type(node);
3293	    line = nd_line(node);
3294	}
3295	/* else */
3296	if (node) {
3297	    ADD_LABEL(cond_seq, elselabel);
3298	    ADD_INSN(cond_seq, line, pop);
3299	    COMPILE_(cond_seq, "else", node, poped);
3300	    ADD_INSNL(cond_seq, line, jump, endlabel);
3301	}
3302	else {
3303	    debugs("== else (implicit)\n");
3304	    ADD_LABEL(cond_seq, elselabel);
3305	    ADD_INSN(cond_seq, nd_line(tempnode), pop);
3306	    if (!poped) {
3307		ADD_INSN(cond_seq, nd_line(tempnode), putnil);
3308	    }
3309	    ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
3310	}
3311
3312	if (only_special_literals) {
3313	    iseq_add_mark_object(iseq, literals);
3314
3315	    ADD_INSN(ret, nd_line(tempnode), dup);
3316	    ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, literals, elselabel);
3317	}
3318
3319	ADD_SEQ(ret, cond_seq);
3320	ADD_SEQ(ret, body_seq);
3321	ADD_LABEL(ret, endlabel);
3322	break;
3323      }
3324      case NODE_WHEN:{
3325	NODE *vals;
3326	NODE *val;
3327	NODE *orig_node = node;
3328	LABEL *endlabel;
3329	DECL_ANCHOR(body_seq);
3330
3331	INIT_ANCHOR(body_seq);
3332	endlabel = NEW_LABEL(line);
3333
3334	while (node && nd_type(node) == NODE_WHEN) {
3335	    LABEL *l1 = NEW_LABEL(line = nd_line(node));
3336	    ADD_LABEL(body_seq, l1);
3337	    COMPILE_(body_seq, "when", node->nd_body, poped);
3338	    ADD_INSNL(body_seq, line, jump, endlabel);
3339
3340	    vals = node->nd_head;
3341	    if (!vals) {
3342		rb_bug("NODE_WHEN: must be NODE_ARRAY, but 0");
3343	    }
3344	    switch (nd_type(vals)) {
3345	      case NODE_ARRAY:
3346		while (vals) {
3347		    val = vals->nd_head;
3348		    COMPILE(ret, "when2", val);
3349		    ADD_INSNL(ret, nd_line(val), branchif, l1);
3350		    vals = vals->nd_next;
3351		}
3352		break;
3353	      case NODE_SPLAT:
3354	      case NODE_ARGSCAT:
3355	      case NODE_ARGSPUSH:
3356		ADD_INSN(ret, nd_line(vals), putnil);
3357		COMPILE(ret, "when2/cond splat", vals);
3358		ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
3359		ADD_INSNL(ret, nd_line(vals), branchif, l1);
3360		break;
3361	      default:
3362		rb_bug("NODE_WHEN: unknown node (%s)",
3363		       ruby_node_name(nd_type(vals)));
3364	    }
3365	    node = node->nd_next;
3366	}
3367	/* else */
3368	COMPILE_(ret, "else", node, poped);
3369	ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
3370
3371	ADD_SEQ(ret, body_seq);
3372	ADD_LABEL(ret, endlabel);
3373
3374	break;
3375      }
3376      case NODE_OPT_N:
3377      case NODE_WHILE:
3378      case NODE_UNTIL:{
3379	LABEL *prev_start_label = iseq->compile_data->start_label;
3380	LABEL *prev_end_label = iseq->compile_data->end_label;
3381	LABEL *prev_redo_label = iseq->compile_data->redo_label;
3382	int prev_loopval_popped = iseq->compile_data->loopval_popped;
3383
3384	struct iseq_compile_data_ensure_node_stack enl;
3385
3386	LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(line);	/* next  */
3387	LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(line);	/* redo  */
3388	LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line);	/* break */
3389	LABEL *end_label = NEW_LABEL(line);
3390
3391	LABEL *next_catch_label = NEW_LABEL(line);
3392	LABEL *tmp_label = NULL;
3393
3394	iseq->compile_data->loopval_popped = 0;
3395	push_ensure_entry(iseq, &enl, 0, 0);
3396
3397	if (type == NODE_OPT_N || node->nd_state == 1) {
3398	    ADD_INSNL(ret, line, jump, next_label);
3399	}
3400	else {
3401	    tmp_label = NEW_LABEL(line);
3402	    ADD_INSNL(ret, line, jump, tmp_label);
3403	}
3404	ADD_INSN(ret, line, putnil);
3405	ADD_LABEL(ret, next_catch_label);
3406	ADD_INSN(ret, line, pop);
3407	ADD_INSNL(ret, line, jump, next_label);
3408	if (tmp_label) ADD_LABEL(ret, tmp_label);
3409
3410	ADD_LABEL(ret, redo_label);
3411	COMPILE_POPED(ret, "while body", node->nd_body);
3412	ADD_LABEL(ret, next_label);	/* next */
3413
3414	if (type == NODE_WHILE) {
3415	    compile_branch_condition(iseq, ret, node->nd_cond,
3416				     redo_label, end_label);
3417	}
3418	else if (type == NODE_UNTIL) {
3419	    /* untile */
3420	    compile_branch_condition(iseq, ret, node->nd_cond,
3421				     end_label, redo_label);
3422	}
3423	else {
3424	    ADD_CALL_RECEIVER(ret, line);
3425	    ADD_CALL(ret, line, ID2SYM(idGets), INT2FIX(0));
3426	    ADD_INSNL(ret, line, branchif, redo_label);
3427	    /* opt_n */
3428	}
3429
3430	ADD_LABEL(ret, end_label);
3431
3432	if (node->nd_state == Qundef) {
3433	    /* ADD_INSN(ret, line, putundef); */
3434	    rb_bug("unsupported: putundef");
3435	}
3436	else {
3437	    ADD_INSN(ret, line, putnil);
3438	}
3439
3440	ADD_LABEL(ret, break_label);	/* break */
3441
3442	if (poped) {
3443	    ADD_INSN(ret, line, pop);
3444	}
3445
3446	ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
3447			0, break_label);
3448	ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, 0,
3449			next_catch_label);
3450	ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
3451			iseq->compile_data->redo_label);
3452
3453	iseq->compile_data->start_label = prev_start_label;
3454	iseq->compile_data->end_label = prev_end_label;
3455	iseq->compile_data->redo_label = prev_redo_label;
3456	iseq->compile_data->loopval_popped = prev_loopval_popped;
3457	iseq->compile_data->ensure_node_stack = iseq->compile_data->ensure_node_stack->prev;
3458	break;
3459      }
3460      case NODE_ITER:
3461      case NODE_FOR:{
3462	VALUE prevblock = iseq->compile_data->current_block;
3463	LABEL *retry_label = NEW_LABEL(line);
3464	LABEL *retry_end_l = NEW_LABEL(line);
3465
3466	ADD_LABEL(ret, retry_label);
3467	if (nd_type(node) == NODE_FOR) {
3468	    COMPILE(ret, "iter caller (for)", node->nd_iter);
3469
3470	    iseq->compile_data->current_block =
3471		NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3472				  ISEQ_TYPE_BLOCK, line);
3473
3474	    ADD_SEND_R(ret, line, ID2SYM(idEach), INT2FIX(0),
3475		       iseq->compile_data->current_block, INT2FIX(0));
3476	}
3477	else {
3478	    iseq->compile_data->current_block =
3479		NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
3480				  ISEQ_TYPE_BLOCK, line);
3481	    COMPILE(ret, "iter caller", node->nd_iter);
3482	}
3483	ADD_LABEL(ret, retry_end_l);
3484
3485	if (poped) {
3486	    ADD_INSN(ret, line, pop);
3487	}
3488
3489	iseq->compile_data->current_block = prevblock;
3490
3491	ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
3492
3493	break;
3494      }
3495      case NODE_BREAK:{
3496	unsigned long level = 0;
3497
3498	if (iseq->compile_data->redo_label != 0) {
3499	    /* while/until */
3500	    LABEL *splabel = NEW_LABEL(0);
3501	    ADD_LABEL(ret, splabel);
3502	    ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
3503	    COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
3504	    add_ensure_iseq(ret, iseq, 0);
3505	    ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
3506	    ADD_ADJUST_RESTORE(ret, splabel);
3507
3508	    if (!poped) {
3509		ADD_INSN(ret, line, putnil);
3510	    }
3511	}
3512	else if (iseq->type == ISEQ_TYPE_BLOCK) {
3513	  break_by_insn:
3514	    /* escape from block */
3515	    COMPILE(ret, "break val (block)", node->nd_stts);
3516	    ADD_INSN1(ret, line, throw, INT2FIX(level | 0x02) /* TAG_BREAK */ );
3517	    if (poped) {
3518		ADD_INSN(ret, line, pop);
3519	    }
3520	}
3521	else if (iseq->type == ISEQ_TYPE_EVAL) {
3522	  break_in_eval:
3523	    COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
3524	}
3525	else {
3526	    rb_iseq_t *ip = iseq->parent_iseq;
3527	    while (ip) {
3528		if (!ip->compile_data) {
3529		    ip = 0;
3530		    break;
3531		}
3532
3533		level++;
3534		if (ip->compile_data->redo_label != 0) {
3535		    level = 0x8000;
3536		    if (ip->compile_data->loopval_popped == 0) {
3537			/* need value */
3538			level |= 0x4000;
3539		    }
3540		    goto break_by_insn;
3541		}
3542		else if (ip->type == ISEQ_TYPE_BLOCK) {
3543		    level <<= 16;
3544		    goto break_by_insn;
3545		}
3546		else if (ip->type == ISEQ_TYPE_EVAL) {
3547		    goto break_in_eval;
3548		}
3549
3550		ip = ip->parent_iseq;
3551	    }
3552	    COMPILE_ERROR((ERROR_ARGS "Invalid break"));
3553	}
3554	break;
3555      }
3556      case NODE_NEXT:{
3557	unsigned long level = 0;
3558
3559	if (iseq->compile_data->redo_label != 0) {
3560	    LABEL *splabel = NEW_LABEL(0);
3561	    debugs("next in while loop\n");
3562	    ADD_LABEL(ret, splabel);
3563	    COMPILE(ret, "next val/valid syntax?", node->nd_stts);
3564	    add_ensure_iseq(ret, iseq, 0);
3565	    ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
3566	    ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
3567	    ADD_ADJUST_RESTORE(ret, splabel);
3568	    if (!poped) {
3569		ADD_INSN(ret, line, putnil);
3570	    }
3571	}
3572	else if (iseq->compile_data->end_label) {
3573	    LABEL *splabel = NEW_LABEL(0);
3574	    debugs("next in block\n");
3575	    ADD_LABEL(ret, splabel);
3576	    ADD_ADJUST(ret, line, iseq->compile_data->start_label);
3577	    COMPILE(ret, "next val", node->nd_stts);
3578	    add_ensure_iseq(ret, iseq, 0);
3579	    ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
3580	    ADD_ADJUST_RESTORE(ret, splabel);
3581
3582	    if (!poped) {
3583		ADD_INSN(ret, line, putnil);
3584	    }
3585	}
3586	else if (iseq->type == ISEQ_TYPE_EVAL) {
3587	  next_in_eval:
3588	    COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
3589	}
3590	else {
3591	    rb_iseq_t *ip;
3592	    ip = iseq;
3593	    while (ip) {
3594		if (!ip->compile_data) {
3595		    ip = 0;
3596		    break;
3597		}
3598
3599		level = 0x8000 | 0x4000;
3600		if (ip->compile_data->redo_label != 0) {
3601		    /* while loop */
3602		    break;
3603		}
3604		else if (ip->type == ISEQ_TYPE_BLOCK) {
3605		    break;
3606		}
3607		else if (ip->type == ISEQ_TYPE_EVAL) {
3608		    goto next_in_eval;
3609		}
3610
3611		ip = ip->parent_iseq;
3612	    }
3613	    if (ip != 0) {
3614		COMPILE(ret, "next val", node->nd_stts);
3615		ADD_INSN1(ret, line, throw, INT2FIX(level | 0x03) /* TAG_NEXT */ );
3616
3617		if (poped) {
3618		    ADD_INSN(ret, line, pop);
3619		}
3620	    }
3621	    else {
3622		COMPILE_ERROR((ERROR_ARGS "Invalid next"));
3623	    }
3624	}
3625	break;
3626      }
3627      case NODE_REDO:{
3628	if (iseq->compile_data->redo_label) {
3629	    LABEL *splabel = NEW_LABEL(0);
3630	    debugs("redo in while");
3631	    ADD_LABEL(ret, splabel);
3632	    ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
3633	    add_ensure_iseq(ret, iseq, 0);
3634	    ADD_INSNL(ret, line, jump, iseq->compile_data->redo_label);
3635	    ADD_ADJUST_RESTORE(ret, splabel);
3636	    if (!poped) {
3637		ADD_INSN(ret, line, putnil);
3638	    }
3639	}
3640	else if (iseq->type == ISEQ_TYPE_EVAL) {
3641	  redo_in_eval:
3642	    COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
3643	}
3644	else if (iseq->compile_data->start_label) {
3645	    LABEL *splabel = NEW_LABEL(0);
3646
3647	    debugs("redo in block");
3648	    ADD_LABEL(ret, splabel);
3649	    add_ensure_iseq(ret, iseq, 0);
3650	    ADD_ADJUST(ret, line, iseq->compile_data->start_label);
3651	    ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
3652	    ADD_ADJUST_RESTORE(ret, splabel);
3653
3654	    if (!poped) {
3655		ADD_INSN(ret, line, putnil);
3656	    }
3657	}
3658	else {
3659	    rb_iseq_t *ip;
3660	    unsigned long level;
3661	    level = 0x8000 | 0x4000;
3662	    ip = iseq;
3663	    while (ip) {
3664		if (!ip->compile_data) {
3665		    ip = 0;
3666		    break;
3667		}
3668
3669		if (ip->compile_data->redo_label != 0) {
3670		    break;
3671		}
3672		else if (ip->type == ISEQ_TYPE_BLOCK) {
3673		    break;
3674		}
3675		else if (ip->type == ISEQ_TYPE_EVAL) {
3676		    goto redo_in_eval;
3677		}
3678
3679		ip = ip->parent_iseq;
3680	    }
3681	    if (ip != 0) {
3682		ADD_INSN(ret, line, putnil);
3683		ADD_INSN1(ret, line, throw, INT2FIX(level | 0x05) /* TAG_REDO */ );
3684
3685		if (poped) {
3686		    ADD_INSN(ret, line, pop);
3687		}
3688	    }
3689	    else {
3690		COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
3691	    }
3692	}
3693	break;
3694      }
3695      case NODE_RETRY:{
3696	if (iseq->type == ISEQ_TYPE_RESCUE) {
3697	    ADD_INSN(ret, line, putnil);
3698	    ADD_INSN1(ret, line, throw, INT2FIX(0x04) /* TAG_RETRY */ );
3699
3700	    if (poped) {
3701		ADD_INSN(ret, line, pop);
3702	    }
3703	}
3704	else {
3705	    COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
3706	}
3707	break;
3708      }
3709      case NODE_BEGIN:{
3710	COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
3711	break;
3712      }
3713      case NODE_RESCUE:{
3714	LABEL *lstart = NEW_LABEL(line);
3715	LABEL *lend = NEW_LABEL(line);
3716	LABEL *lcont = NEW_LABEL(line);
3717	VALUE rescue = NEW_CHILD_ISEQVAL(
3718	    node->nd_resq,
3719	    rb_str_concat(rb_str_new2("rescue in "), iseq->location.label),
3720	    ISEQ_TYPE_RESCUE, line);
3721
3722	ADD_LABEL(ret, lstart);
3723	COMPILE(ret, "rescue head", node->nd_head);
3724	ADD_LABEL(ret, lend);
3725	if (node->nd_else) {
3726	    ADD_INSN(ret, line, pop);
3727	    COMPILE(ret, "rescue else", node->nd_else);
3728	}
3729	ADD_INSN(ret, line, nop);
3730	ADD_LABEL(ret, lcont);
3731
3732	if (poped) {
3733	    ADD_INSN(ret, line, pop);
3734	}
3735
3736	/* register catch entry */
3737	ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
3738	ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
3739	break;
3740      }
3741      case NODE_RESBODY:{
3742	NODE *resq = node;
3743	NODE *narg;
3744	LABEL *label_miss, *label_hit;
3745
3746	while (resq) {
3747	    label_miss = NEW_LABEL(line);
3748	    label_hit = NEW_LABEL(line);
3749
3750	    narg = resq->nd_args;
3751	    if (narg) {
3752		switch (nd_type(narg)) {
3753		  case NODE_ARRAY:
3754		    while (narg) {
3755			ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
3756			COMPILE(ret, "rescue arg", narg->nd_head);
3757			ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
3758			ADD_INSNL(ret, line, branchif, label_hit);
3759			narg = narg->nd_next;
3760		    }
3761		    break;
3762		  case NODE_SPLAT:
3763		  case NODE_ARGSCAT:
3764		  case NODE_ARGSPUSH:
3765		    ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
3766		    COMPILE(ret, "rescue/cond splat", narg);
3767		    ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
3768		    ADD_INSNL(ret, line, branchif, label_hit);
3769		    break;
3770		  default:
3771		    rb_bug("NODE_RESBODY: unknown node (%s)",
3772			   ruby_node_name(nd_type(narg)));
3773		}
3774	    }
3775	    else {
3776		ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
3777		ADD_INSN1(ret, line, putobject, rb_eStandardError);
3778		ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
3779		ADD_INSNL(ret, line, branchif, label_hit);
3780	    }
3781	    ADD_INSNL(ret, line, jump, label_miss);
3782	    ADD_LABEL(ret, label_hit);
3783	    COMPILE(ret, "resbody body", resq->nd_body);
3784	    if (iseq->compile_data->option->tailcall_optimization) {
3785		ADD_INSN(ret, line, nop);
3786	    }
3787	    ADD_INSN(ret, line, leave);
3788	    ADD_LABEL(ret, label_miss);
3789	    resq = resq->nd_head;
3790	}
3791	break;
3792      }
3793      case NODE_ENSURE:{
3794	DECL_ANCHOR(ensr);
3795	VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
3796					 rb_str_concat(rb_str_new2
3797						       ("ensure in "),
3798						       iseq->location.label),
3799					 ISEQ_TYPE_ENSURE, line);
3800	LABEL *lstart = NEW_LABEL(line);
3801	LABEL *lend = NEW_LABEL(line);
3802	LABEL *lcont = NEW_LABEL(line);
3803	struct ensure_range er;
3804	struct iseq_compile_data_ensure_node_stack enl;
3805	struct ensure_range *erange;
3806
3807	INIT_ANCHOR(ensr);
3808	COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
3809
3810	er.begin = lstart;
3811	er.end = lend;
3812	er.next = 0;
3813	push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
3814
3815	ADD_LABEL(ret, lstart);
3816	COMPILE_(ret, "ensure head", node->nd_head, poped);
3817	ADD_LABEL(ret, lend);
3818	if (ensr->anchor.next == 0) {
3819	    ADD_INSN(ret, line, nop);
3820	}
3821	else {
3822	    ADD_SEQ(ret, ensr);
3823	}
3824	ADD_LABEL(ret, lcont);
3825
3826	erange = iseq->compile_data->ensure_node_stack->erange;
3827	while (erange) {
3828	    ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
3829			    ensure, lcont);
3830	    erange = erange->next;
3831	}
3832
3833	iseq->compile_data->ensure_node_stack = enl.prev;
3834	break;
3835      }
3836
3837      case NODE_AND:
3838      case NODE_OR:{
3839	LABEL *end_label = NEW_LABEL(line);
3840	COMPILE(ret, "nd_1st", node->nd_1st);
3841	if (!poped) {
3842	    ADD_INSN(ret, line, dup);
3843	}
3844	if (type == NODE_AND) {
3845	    ADD_INSNL(ret, line, branchunless, end_label);
3846	}
3847	else {
3848	    ADD_INSNL(ret, line, branchif, end_label);
3849	}
3850	if (!poped) {
3851	    ADD_INSN(ret, line, pop);
3852	}
3853	COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
3854	ADD_LABEL(ret, end_label);
3855	break;
3856      }
3857
3858      case NODE_MASGN:{
3859	compile_massign(iseq, ret, node, poped);
3860	break;
3861      }
3862
3863      case NODE_LASGN:{
3864	ID id = node->nd_vid;
3865	int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
3866
3867	debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
3868	COMPILE(ret, "rvalue", node->nd_value);
3869
3870	if (!poped) {
3871	    ADD_INSN(ret, line, dup);
3872	}
3873	ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
3874
3875	break;
3876      }
3877      case NODE_DASGN:
3878      case NODE_DASGN_CURR:{
3879	int idx, lv, ls;
3880	COMPILE(ret, "dvalue", node->nd_value);
3881	debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
3882
3883	if (!poped) {
3884	    ADD_INSN(ret, line, dup);
3885	}
3886
3887	idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
3888
3889	if (idx < 0) {
3890	    rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
3891	}
3892
3893	ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
3894	break;
3895      }
3896      case NODE_GASGN:{
3897	COMPILE(ret, "lvalue", node->nd_value);
3898
3899	if (!poped) {
3900	    ADD_INSN(ret, line, dup);
3901	}
3902	ADD_INSN1(ret, line, setglobal,
3903		  ((VALUE)node->nd_entry | 1));
3904	break;
3905      }
3906      case NODE_IASGN:
3907      case NODE_IASGN2:{
3908	COMPILE(ret, "lvalue", node->nd_value);
3909	if (!poped) {
3910	    ADD_INSN(ret, line, dup);
3911	}
3912	ADD_INSN2(ret, line, setinstancevariable,
3913		  ID2SYM(node->nd_vid), INT2FIX(iseq->ic_size++));
3914	break;
3915      }
3916      case NODE_CDECL:{
3917	COMPILE(ret, "lvalue", node->nd_value);
3918
3919	if (!poped) {
3920	    ADD_INSN(ret, line, dup);
3921	}
3922
3923	if (node->nd_vid) {
3924	    ADD_INSN1(ret, line, putspecialobject,
3925		      INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3926	    ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
3927	}
3928	else {
3929	    compile_cpath(ret, iseq, node->nd_else);
3930	    ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
3931	}
3932	break;
3933      }
3934      case NODE_CVASGN:{
3935	COMPILE(ret, "cvasgn val", node->nd_value);
3936	if (!poped) {
3937	    ADD_INSN(ret, line, dup);
3938	}
3939	ADD_INSN1(ret, line, setclassvariable,
3940		  ID2SYM(node->nd_vid));
3941	break;
3942      }
3943      case NODE_OP_ASGN1: {
3944	DECL_ANCHOR(args);
3945	VALUE argc;
3946	VALUE flag = 0;
3947	ID id = node->nd_mid;
3948	int boff = 0;
3949
3950	/*
3951	 * a[x] (op)= y
3952	 *
3953	 * nil       # nil
3954	 * eval a    # nil a
3955	 * eval x    # nil a x
3956	 * dupn 2    # nil a x a x
3957	 * send :[]  # nil a x a[x]
3958	 * eval y    # nil a x a[x] y
3959	 * send op   # nil a x ret
3960	 * setn 3    # ret a x ret
3961	 * send []=  # ret ?
3962	 * pop       # ret
3963	 */
3964
3965	/*
3966	 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
3967	 * NODE_OP_ASGN nd_recv
3968	 *              nd_args->nd_head
3969	 *              nd_args->nd_body
3970	 *              nd_mid
3971	 */
3972
3973	if (!poped) {
3974	    ADD_INSN(ret, line, putnil);
3975	}
3976	COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
3977	switch (nd_type(node->nd_args->nd_head)) {
3978	  case NODE_ZARRAY:
3979	    argc = INT2FIX(0);
3980	    break;
3981	  case NODE_BLOCK_PASS:
3982	    boff = 1;
3983	  default:
3984	    INIT_ANCHOR(args);
3985	    argc = setup_args(iseq, args, node->nd_args->nd_head, &flag);
3986	    ADD_SEQ(ret, args);
3987	}
3988	ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
3989	ADD_SEND_R(ret, line, ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
3990
3991	if (id == 0 || id == 1) {
3992	    /* 0: or, 1: and
3993	       a[x] ||= y
3994
3995	       unless/if a[x]
3996	       a[x]= y
3997	       else
3998	       nil
3999	       end
4000	    */
4001	    LABEL *label = NEW_LABEL(line);
4002	    LABEL *lfin = NEW_LABEL(line);
4003
4004	    ADD_INSN(ret, line, dup);
4005	    if (id == 0) {
4006		/* or */
4007		ADD_INSNL(ret, line, branchif, label);
4008	    }
4009	    else {
4010		/* and */
4011		ADD_INSNL(ret, line, branchunless, label);
4012	    }
4013	    ADD_INSN(ret, line, pop);
4014
4015	    COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
4016	    if (!poped) {
4017		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
4018	    }
4019	    if (flag & VM_CALL_ARGS_SPLAT) {
4020		ADD_INSN1(ret, line, newarray, INT2FIX(1));
4021		if (boff > 0) {
4022		    ADD_INSN1(ret, line, dupn, INT2FIX(3));
4023		    ADD_INSN(ret, line, swap);
4024		    ADD_INSN(ret, line, pop);
4025		}
4026		ADD_INSN(ret, line, concatarray);
4027		if (boff > 0) {
4028		    ADD_INSN1(ret, line, setn, INT2FIX(3));
4029		    ADD_INSN(ret, line, pop);
4030		    ADD_INSN(ret, line, pop);
4031		}
4032		ADD_SEND_R(ret, line, ID2SYM(idASET),
4033			   argc, Qfalse, LONG2FIX(flag));
4034	    }
4035	    else {
4036		if (boff > 0)
4037		    ADD_INSN(ret, line, swap);
4038		ADD_SEND_R(ret, line, ID2SYM(idASET),
4039			   FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
4040	    }
4041	    ADD_INSN(ret, line, pop);
4042	    ADD_INSNL(ret, line, jump, lfin);
4043	    ADD_LABEL(ret, label);
4044	    if (!poped) {
4045		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
4046	    }
4047	    ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
4048	    ADD_LABEL(ret, lfin);
4049	}
4050	else {
4051	    COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
4052	    ADD_SEND(ret, line, ID2SYM(id), INT2FIX(1));
4053	    if (!poped) {
4054		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
4055	    }
4056	    if (flag & VM_CALL_ARGS_SPLAT) {
4057		ADD_INSN1(ret, line, newarray, INT2FIX(1));
4058		if (boff > 0) {
4059		    ADD_INSN1(ret, line, dupn, INT2FIX(3));
4060		    ADD_INSN(ret, line, swap);
4061		    ADD_INSN(ret, line, pop);
4062		}
4063		ADD_INSN(ret, line, concatarray);
4064		if (boff > 0) {
4065		    ADD_INSN1(ret, line, setn, INT2FIX(3));
4066		    ADD_INSN(ret, line, pop);
4067		    ADD_INSN(ret, line, pop);
4068		}
4069		ADD_SEND_R(ret, line, ID2SYM(idASET),
4070			   argc, Qfalse, LONG2FIX(flag));
4071	    }
4072	    else {
4073		if (boff > 0)
4074		    ADD_INSN(ret, line, swap);
4075		ADD_SEND_R(ret, line, ID2SYM(idASET),
4076			   FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
4077	    }
4078	    ADD_INSN(ret, line, pop);
4079	}
4080
4081	break;
4082      }
4083      case NODE_OP_ASGN2:{
4084	ID atype = node->nd_next->nd_mid;
4085	LABEL *lfin = NEW_LABEL(line);
4086	LABEL *lcfin = NEW_LABEL(line);
4087	/*
4088	  class C; attr_accessor :c; end
4089	  r = C.new
4090	  r.a &&= v # asgn2
4091
4092	  eval r    # r
4093	  dup       # r r
4094	  eval r.a  # r o
4095
4096	  # or
4097	  dup       # r o o
4098	  if lcfin  # r o
4099	  pop       # r
4100	  eval v    # r v
4101	  swap      # v r
4102	  topn 1    # v r v
4103	  send a=   # v ?
4104	  jump lfin # v ?
4105
4106	  lcfin:      # r o
4107	  swap      # o r
4108
4109	  lfin:       # o ?
4110	  pop       # o
4111
4112	  # and
4113	  dup       # r o o
4114	  unless lcfin
4115	  pop       # r
4116	  eval v    # r v
4117	  swap      # v r
4118	  topn 1    # v r v
4119	  send a=   # v ?
4120	  jump lfin # v ?
4121
4122	  # others
4123	  eval v    # r o v
4124	  send ??   # r w
4125	  send a=   # w
4126
4127	*/
4128
4129	COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
4130	ADD_INSN(ret, line, dup);
4131	ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_vid),
4132		 INT2FIX(0));
4133
4134	if (atype == 0 || atype == 1) {	/* 0: OR or 1: AND */
4135	    ADD_INSN(ret, line, dup);
4136	    if (atype == 0) {
4137		ADD_INSNL(ret, line, branchif, lcfin);
4138	    }
4139	    else {
4140		ADD_INSNL(ret, line, branchunless, lcfin);
4141	    }
4142	    ADD_INSN(ret, line, pop);
4143	    COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
4144	    ADD_INSN(ret, line, swap);
4145	    ADD_INSN1(ret, line, topn, INT2FIX(1));
4146	    ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
4147		     INT2FIX(1));
4148	    ADD_INSNL(ret, line, jump, lfin);
4149
4150	    ADD_LABEL(ret, lcfin);
4151	    ADD_INSN(ret, line, swap);
4152
4153	    ADD_LABEL(ret, lfin);
4154	    ADD_INSN(ret, line, pop);
4155	    if (poped) {
4156		/* we can apply more optimize */
4157		ADD_INSN(ret, line, pop);
4158	    }
4159	}
4160	else {
4161	    COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
4162	    ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_mid),
4163		     INT2FIX(1));
4164	    if (!poped) {
4165		ADD_INSN(ret, line, swap);
4166		ADD_INSN1(ret, line, topn, INT2FIX(1));
4167	    }
4168	    ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
4169		     INT2FIX(1));
4170	    ADD_INSN(ret, line, pop);
4171	}
4172	break;
4173      }
4174      case NODE_OP_CDECL: {
4175	LABEL *lfin = 0;
4176	LABEL *lassign = 0;
4177	ID mid;
4178
4179	switch (nd_type(node->nd_head)) {
4180	  case NODE_COLON3:
4181	    ADD_INSN1(ret, line, putobject, rb_cObject);
4182	    break;
4183	  case NODE_COLON2:
4184	    COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head);
4185	    break;
4186	  default:
4187	    do {
4188		COMPILE_ERROR((ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
4189			       ruby_node_name(nd_type(node->nd_head))));
4190	    } while (0);
4191	    return COMPILE_NG;
4192	}
4193	mid = node->nd_head->nd_mid;
4194	/* cref */
4195	if (node->nd_aid == 0) {
4196	    lassign = NEW_LABEL(line);
4197	    ADD_INSN(ret, line, dup); /* cref cref */
4198	    ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
4199		      ID2SYM(mid), Qfalse); /* cref bool */
4200	    ADD_INSNL(ret, line, branchunless, lassign); /* cref */
4201	}
4202	ADD_INSN(ret, line, dup); /* cref cref */
4203	ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
4204
4205	if (node->nd_aid == 0 || node->nd_aid == 1) {
4206	    lfin = NEW_LABEL(line);
4207	    if (!poped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
4208	    if (node->nd_aid == 0)
4209		ADD_INSNL(ret, line, branchif, lfin);
4210	    else
4211		ADD_INSNL(ret, line, branchunless, lfin);
4212	    /* cref [obj] */
4213	    if (!poped) ADD_INSN(ret, line, pop); /* cref */
4214	    if (lassign) ADD_LABEL(ret, lassign);
4215	    COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
4216	    /* cref value */
4217	    if (poped)
4218		ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
4219	    else {
4220		ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
4221		ADD_INSN(ret, line, swap); /* cref value value cref */
4222	    }
4223	    ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
4224	    ADD_LABEL(ret, lfin);			    /* cref [value] */
4225	    if (!poped) ADD_INSN(ret, line, swap); /* [value] cref */
4226	    ADD_INSN(ret, line, pop); /* [value] */
4227	}
4228	else {
4229	    COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
4230	    /* cref obj value */
4231	    ADD_CALL(ret, line, ID2SYM(node->nd_aid), INT2FIX(1));
4232	    /* cref value */
4233	    ADD_INSN(ret, line, swap); /* value cref */
4234	    if (!poped) {
4235		ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
4236		ADD_INSN(ret, line, swap); /* value value cref */
4237	    }
4238	    ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
4239	}
4240	break;
4241      }
4242      case NODE_OP_ASGN_AND:
4243      case NODE_OP_ASGN_OR:{
4244	LABEL *lfin = NEW_LABEL(line);
4245	LABEL *lassign;
4246
4247	if (nd_type(node) == NODE_OP_ASGN_OR) {
4248	    LABEL *lfinish[2];
4249	    lfinish[0] = lfin;
4250	    lfinish[1] = 0;
4251	    defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
4252	    lassign = lfinish[1];
4253	    if (!lassign) {
4254		lassign = NEW_LABEL(line);
4255	    }
4256	    ADD_INSNL(ret, line, branchunless, lassign);
4257	}
4258	else {
4259	    lassign = NEW_LABEL(line);
4260	}
4261
4262	COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
4263	ADD_INSN(ret, line, dup);
4264
4265	if (nd_type(node) == NODE_OP_ASGN_AND) {
4266	    ADD_INSNL(ret, line, branchunless, lfin);
4267	}
4268	else {
4269	    ADD_INSNL(ret, line, branchif, lfin);
4270	}
4271
4272	ADD_INSN(ret, line, pop);
4273	ADD_LABEL(ret, lassign);
4274	COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
4275	ADD_LABEL(ret, lfin);
4276
4277	if (poped) {
4278	    /* we can apply more optimize */
4279	    ADD_INSN(ret, line, pop);
4280	}
4281	break;
4282      }
4283      case NODE_CALL:
4284      case NODE_FCALL:
4285      case NODE_VCALL:{		/* VCALL: variable or call */
4286	/*
4287	  call:  obj.method(...)
4288	  fcall: func(...)
4289	  vcall: func
4290	*/
4291	DECL_ANCHOR(recv);
4292	DECL_ANCHOR(args);
4293	ID mid = node->nd_mid;
4294	VALUE argc;
4295	VALUE flag = 0;
4296	VALUE parent_block = iseq->compile_data->current_block;
4297	iseq->compile_data->current_block = Qfalse;
4298
4299	INIT_ANCHOR(recv);
4300	INIT_ANCHOR(args);
4301#if SUPPORT_JOKE
4302	if (nd_type(node) == NODE_VCALL) {
4303	    ID id_bitblt;
4304	    ID id_answer;
4305
4306	    CONST_ID(id_bitblt, "bitblt");
4307	    CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
4308
4309	    if (mid == id_bitblt) {
4310		ADD_INSN(ret, line, bitblt);
4311		break;
4312	    }
4313	    else if (mid == id_answer) {
4314		ADD_INSN(ret, line, answer);
4315		break;
4316	    }
4317	}
4318	/* only joke */
4319	{
4320	    ID goto_id;
4321	    ID label_id;
4322
4323	    CONST_ID(goto_id, "__goto__");
4324	    CONST_ID(label_id, "__label__");
4325
4326	    if (nd_type(node) == NODE_FCALL &&
4327		(mid == goto_id || mid == label_id)) {
4328		LABEL *label;
4329		st_data_t data;
4330		st_table *labels_table = iseq->compile_data->labels_table;
4331		ID label_name;
4332
4333		if (!labels_table) {
4334		    labels_table = st_init_numtable();
4335		    iseq->compile_data->labels_table = labels_table;
4336		}
4337		if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
4338		    SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
4339
4340		    label_name = SYM2ID(node->nd_args->nd_head->nd_lit);
4341		    if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
4342			label = NEW_LABEL(line);
4343			label->position = line;
4344			st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
4345		    }
4346		    else {
4347			label = (LABEL *)data;
4348		    }
4349		}
4350		else {
4351		    COMPILE_ERROR((ERROR_ARGS "invalid goto/label format"));
4352		}
4353
4354
4355		if (mid == goto_id) {
4356		    ADD_INSNL(ret, line, jump, label);
4357		}
4358		else {
4359		    ADD_LABEL(ret, label);
4360		}
4361		break;
4362	    }
4363	}
4364#endif
4365	/* receiver */
4366	if (type == NODE_CALL) {
4367	    COMPILE(recv, "recv", node->nd_recv);
4368	}
4369	else if (type == NODE_FCALL || type == NODE_VCALL) {
4370	    ADD_CALL_RECEIVER(recv, line);
4371	}
4372
4373	/* args */
4374	if (nd_type(node) != NODE_VCALL) {
4375	    argc = setup_args(iseq, args, node->nd_args, &flag);
4376	}
4377	else {
4378	    argc = INT2FIX(0);
4379	}
4380
4381	ADD_SEQ(ret, recv);
4382	ADD_SEQ(ret, args);
4383
4384	debugp_param("call args argc", argc);
4385	debugp_param("call method", ID2SYM(mid));
4386
4387	switch (nd_type(node)) {
4388	  case NODE_VCALL:
4389	    flag |= VM_CALL_VCALL;
4390	    /* VCALL is funcall, so fall through */
4391	  case NODE_FCALL:
4392	    flag |= VM_CALL_FCALL;
4393	}
4394
4395	ADD_SEND_R(ret, line, ID2SYM(mid),
4396		   argc, parent_block, LONG2FIX(flag));
4397
4398	if (poped) {
4399	    ADD_INSN(ret, line, pop);
4400	}
4401	break;
4402      }
4403      case NODE_SUPER:
4404      case NODE_ZSUPER:{
4405	DECL_ANCHOR(args);
4406	int argc;
4407	VALUE flag = 0;
4408	VALUE parent_block = iseq->compile_data->current_block;
4409
4410	INIT_ANCHOR(args);
4411	iseq->compile_data->current_block = Qfalse;
4412	if (nd_type(node) == NODE_SUPER) {
4413	    VALUE vargc = setup_args(iseq, args, node->nd_args, &flag);
4414	    argc = FIX2INT(vargc);
4415	}
4416	else {
4417	    /* NODE_ZSUPER */
4418	    int i;
4419	    rb_iseq_t *liseq = iseq->local_iseq;
4420	    int lvar_level = get_lvar_level(iseq);
4421
4422	    argc = liseq->argc;
4423
4424	    /* normal arguments */
4425	    for (i = 0; i < liseq->argc; i++) {
4426		int idx = liseq->local_size - i;
4427		ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4428	    }
4429
4430	    if (!liseq->arg_simple) {
4431		if (liseq->arg_opts) {
4432		    /* optional arguments */
4433		    int j;
4434		    for (j = 0; j < liseq->arg_opts - 1; j++) {
4435			int idx = liseq->local_size - (i + j);
4436			ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4437		    }
4438		    i += j;
4439		    argc = i;
4440		}
4441
4442		if (liseq->arg_rest != -1) {
4443		    /* rest argument */
4444		    int idx = liseq->local_size - liseq->arg_rest;
4445		    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4446		    argc = liseq->arg_rest + 1;
4447		    flag |= VM_CALL_ARGS_SPLAT;
4448		}
4449
4450		if (liseq->arg_post_len) {
4451		    /* post arguments */
4452		    int post_len = liseq->arg_post_len;
4453		    int post_start = liseq->arg_post_start;
4454
4455		    if (liseq->arg_rest != -1) {
4456			int j;
4457			for (j=0; j<post_len; j++) {
4458			    int idx = liseq->local_size - (post_start + j);
4459			    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4460			}
4461			ADD_INSN1(args, line, newarray, INT2FIX(j));
4462			ADD_INSN (args, line, concatarray);
4463			/* argc is setteled at above */
4464		    }
4465		    else {
4466			int j;
4467			for (j=0; j<post_len; j++) {
4468			    int idx = liseq->local_size - (post_start + j);
4469			    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4470			}
4471			argc = post_len + post_start;
4472		    }
4473		}
4474
4475		if (liseq->arg_keyword >= 0) {
4476		    int local_size = liseq->local_size;
4477		    int idx = local_size - liseq->arg_keyword;
4478		    argc++;
4479		    ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4480		    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4481		    ADD_SEND (args, line, ID2SYM(rb_intern("dup")), INT2FIX(0));
4482		    for (i = 0; i < liseq->arg_keywords; ++i) {
4483			ID id = liseq->arg_keyword_table[i];
4484			idx = local_size - get_local_var_idx(liseq, id);
4485			ADD_INSN1(args, line, putobject, ID2SYM(id));
4486			ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
4487		    }
4488		    ADD_SEND(args, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i * 2 + 1));
4489		    if (liseq->arg_rest != -1) {
4490			ADD_INSN1(args, line, newarray, INT2FIX(1));
4491			ADD_INSN (args, line, concatarray);
4492			--argc;
4493		    }
4494		}
4495	    }
4496	}
4497
4498	/* dummy receiver */
4499	ADD_INSN1(ret, line, putobject, nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
4500	ADD_SEQ(ret, args);
4501	ADD_INSN1(ret, line, invokesuper, new_callinfo(iseq, 0, argc, parent_block,
4502								flag | VM_CALL_SUPER | VM_CALL_FCALL));
4503
4504	if (poped) {
4505	    ADD_INSN(ret, line, pop);
4506	}
4507	break;
4508      }
4509      case NODE_ARRAY:{
4510	compile_array_(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, poped);
4511	break;
4512      }
4513      case NODE_ZARRAY:{
4514	if (!poped) {
4515	    ADD_INSN1(ret, line, newarray, INT2FIX(0));
4516	}
4517	break;
4518      }
4519      case NODE_VALUES:{
4520	NODE *n = node;
4521	while (n) {
4522	    COMPILE(ret, "values item", n->nd_head);
4523	    n = n->nd_next;
4524	}
4525	ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
4526	if (poped) {
4527	    ADD_INSN(ret, line, pop);
4528	}
4529	break;
4530      }
4531      case NODE_HASH:{
4532	DECL_ANCHOR(list);
4533	int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
4534
4535	INIT_ANCHOR(list);
4536	switch (type) {
4537	  case NODE_ARRAY:
4538	    compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH);
4539	    ADD_SEQ(ret, list);
4540	    break;
4541
4542	  case NODE_ZARRAY:
4543	    ADD_INSN1(ret, line, newhash, INT2FIX(0));
4544	    break;
4545
4546	  default:
4547	    rb_bug("can't make hash with this node: %s", ruby_node_name(type));
4548	}
4549
4550	if (poped) {
4551	    ADD_INSN(ret, line, pop);
4552	}
4553	break;
4554      }
4555      case NODE_RETURN:{
4556	rb_iseq_t *is = iseq;
4557
4558	if (is) {
4559	    if (is->type == ISEQ_TYPE_TOP) {
4560		COMPILE_ERROR((ERROR_ARGS "Invalid return"));
4561	    }
4562	    else {
4563		LABEL *splabel = 0;
4564
4565		if (is->type == ISEQ_TYPE_METHOD) {
4566		    splabel = NEW_LABEL(0);
4567		    ADD_LABEL(ret, splabel);
4568		    ADD_ADJUST(ret, line, 0);
4569		}
4570
4571		COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
4572
4573		if (is->type == ISEQ_TYPE_METHOD) {
4574		    add_ensure_iseq(ret, iseq, 1);
4575		    ADD_TRACE(ret, line, RUBY_EVENT_RETURN);
4576		    ADD_INSN(ret, line, leave);
4577		    ADD_ADJUST_RESTORE(ret, splabel);
4578
4579		    if (!poped) {
4580			ADD_INSN(ret, line, putnil);
4581		    }
4582		}
4583		else {
4584		    ADD_INSN1(ret, line, throw, INT2FIX(0x01) /* TAG_RETURN */ );
4585		    if (poped) {
4586			ADD_INSN(ret, line, pop);
4587		    }
4588		}
4589	    }
4590	}
4591	break;
4592      }
4593      case NODE_YIELD:{
4594	DECL_ANCHOR(args);
4595	VALUE argc;
4596	VALUE flag = 0;
4597
4598	INIT_ANCHOR(args);
4599	if (iseq->type == ISEQ_TYPE_TOP) {
4600	    COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
4601	}
4602
4603	if (node->nd_head) {
4604	    argc = setup_args(iseq, args, node->nd_head, &flag);
4605	}
4606	else {
4607	    argc = INT2FIX(0);
4608	}
4609
4610	ADD_SEQ(ret, args);
4611	ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), 0, flag));
4612
4613	if (poped) {
4614	    ADD_INSN(ret, line, pop);
4615	}
4616	break;
4617      }
4618      case NODE_LVAR:{
4619	if (!poped) {
4620	    ID id = node->nd_vid;
4621	    int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
4622
4623	    debugs("id: %s idx: %d\n", rb_id2name(id), idx);
4624	    ADD_INSN2(ret, line, getlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
4625	}
4626	break;
4627      }
4628      case NODE_DVAR:{
4629	int lv, idx, ls;
4630	debugi("nd_vid", node->nd_vid);
4631	if (!poped) {
4632	    idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
4633	    if (idx < 0) {
4634		rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
4635	    }
4636	    ADD_INSN2(ret, line, getlocal, INT2FIX(ls - idx), INT2FIX(lv));
4637	}
4638	break;
4639      }
4640      case NODE_GVAR:{
4641	ADD_INSN1(ret, line, getglobal,
4642		  ((VALUE)node->nd_entry | 1));
4643	if (poped) {
4644	    ADD_INSN(ret, line, pop);
4645	}
4646	break;
4647      }
4648      case NODE_IVAR:{
4649	debugi("nd_vid", node->nd_vid);
4650	if (!poped) {
4651	    ADD_INSN2(ret, line, getinstancevariable,
4652		      ID2SYM(node->nd_vid), INT2FIX(iseq->ic_size++));
4653	}
4654	break;
4655      }
4656      case NODE_CONST:{
4657	debugi("nd_vid", node->nd_vid);
4658
4659	if (iseq->compile_data->option->inline_const_cache) {
4660	    LABEL *lend = NEW_LABEL(line);
4661	    int ic_index = iseq->ic_size++;
4662
4663	    ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
4664	    ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
4665	    ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
4666	    ADD_LABEL(ret, lend);
4667	}
4668	else {
4669	    ADD_INSN(ret, line, putnil);
4670	    ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
4671	}
4672
4673	if (poped) {
4674	    ADD_INSN(ret, line, pop);
4675	}
4676	break;
4677      }
4678      case NODE_CVAR:{
4679	if (!poped) {
4680	    ADD_INSN1(ret, line, getclassvariable,
4681		      ID2SYM(node->nd_vid));
4682	}
4683	break;
4684      }
4685      case NODE_NTH_REF:{
4686        if (!poped) {
4687	    ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~'  */,
4688		      INT2FIX(node->nd_nth << 1));
4689	}
4690	break;
4691      }
4692      case NODE_BACK_REF:{
4693	if (!poped) {
4694	    ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
4695		      INT2FIX(0x01 | (node->nd_nth << 1)));
4696	}
4697	break;
4698      }
4699      case NODE_MATCH:
4700      case NODE_MATCH2:
4701      case NODE_MATCH3:{
4702	DECL_ANCHOR(recv);
4703	DECL_ANCHOR(val);
4704
4705	INIT_ANCHOR(recv);
4706	INIT_ANCHOR(val);
4707	switch (nd_type(node)) {
4708	  case NODE_MATCH:
4709	    ADD_INSN1(recv, line, putobject, node->nd_lit);
4710	    ADD_INSN2(val, line, getspecial, INT2FIX(0),
4711		      INT2FIX(0));
4712	    break;
4713	  case NODE_MATCH2:
4714	    COMPILE(recv, "receiver", node->nd_recv);
4715	    COMPILE(val, "value", node->nd_value);
4716	    break;
4717	  case NODE_MATCH3:
4718	    COMPILE(recv, "receiver", node->nd_value);
4719	    COMPILE(val, "value", node->nd_recv);
4720	    break;
4721	}
4722
4723	if (iseq->compile_data->option->specialized_instruction) {
4724	    /* TODO: detect by node */
4725	    if (recv->last == recv->anchor.next &&
4726		INSN_OF(recv->last) == BIN(putobject) &&
4727		nd_type(node) == NODE_MATCH2) {
4728		ADD_SEQ(ret, val);
4729		ADD_INSN1(ret, line, opt_regexpmatch1,
4730			  OPERAND_AT(recv->last, 0));
4731	    }
4732	    else {
4733		ADD_SEQ(ret, recv);
4734		ADD_SEQ(ret, val);
4735		ADD_INSN(ret, line, opt_regexpmatch2);
4736	    }
4737	}
4738	else {
4739	    ADD_SEQ(ret, recv);
4740	    ADD_SEQ(ret, val);
4741	    ADD_SEND(ret, line, ID2SYM(idEqTilde), INT2FIX(1));
4742	}
4743
4744	if (poped) {
4745	    ADD_INSN(ret, line, pop);
4746	}
4747	break;
4748      }
4749      case NODE_LIT:{
4750	debugp_param("lit", node->nd_lit);
4751	if (!poped) {
4752	    ADD_INSN1(ret, line, putobject, node->nd_lit);
4753	}
4754	break;
4755      }
4756      case NODE_STR:{
4757	debugp_param("nd_lit", node->nd_lit);
4758	if (!poped) {
4759	    OBJ_FREEZE(node->nd_lit);
4760	    ADD_INSN1(ret, line, putstring, node->nd_lit);
4761	}
4762	break;
4763      }
4764      case NODE_DSTR:{
4765	compile_dstr(iseq, ret, node);
4766
4767	if (poped) {
4768	    ADD_INSN(ret, line, pop);
4769	}
4770	break;
4771      }
4772      case NODE_XSTR:{
4773	OBJ_FREEZE(node->nd_lit);
4774	ADD_CALL_RECEIVER(ret, line);
4775	ADD_INSN1(ret, line, putobject, node->nd_lit);
4776	ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
4777
4778	if (poped) {
4779	    ADD_INSN(ret, line, pop);
4780	}
4781	break;
4782      }
4783      case NODE_DXSTR:{
4784	ADD_CALL_RECEIVER(ret, line);
4785	compile_dstr(iseq, ret, node);
4786	ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
4787
4788	if (poped) {
4789	    ADD_INSN(ret, line, pop);
4790	}
4791	break;
4792      }
4793      case NODE_EVSTR:{
4794	COMPILE(ret, "nd_body", node->nd_body);
4795
4796	if (poped) {
4797	    ADD_INSN(ret, line, pop);
4798	}
4799	else {
4800	    ADD_INSN(ret, line, tostring);
4801	}
4802	break;
4803      }
4804      case NODE_DREGX:{
4805	compile_dregx(iseq, ret, node);
4806
4807	if (poped) {
4808	    ADD_INSN(ret, line, pop);
4809	}
4810	break;
4811      }
4812      case NODE_DREGX_ONCE:{
4813	/* TODO: once? */
4814	LABEL *lend = NEW_LABEL(line);
4815	int ic_index = iseq->ic_size++;
4816
4817	ADD_INSN2(ret, line, onceinlinecache, lend, INT2FIX(ic_index));
4818	ADD_INSN(ret, line, pop);
4819
4820	compile_dregx(iseq, ret, node);
4821
4822	ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
4823	ADD_LABEL(ret, lend);
4824
4825	if (poped) {
4826	    ADD_INSN(ret, line, pop);
4827	}
4828	break;
4829      }
4830      case NODE_ARGSCAT:{
4831	if (poped) {
4832	    COMPILE(ret, "argscat head", node->nd_head);
4833	    ADD_INSN1(ret, line, splatarray, Qfalse);
4834	    ADD_INSN(ret, line, pop);
4835	    COMPILE(ret, "argscat body", node->nd_body);
4836	    ADD_INSN1(ret, line, splatarray, Qfalse);
4837	    ADD_INSN(ret, line, pop);
4838	}
4839	else {
4840	    COMPILE(ret, "argscat head", node->nd_head);
4841	    COMPILE(ret, "argscat body", node->nd_body);
4842	    ADD_INSN(ret, line, concatarray);
4843	}
4844	break;
4845      }
4846      case NODE_ARGSPUSH:{
4847	if (poped) {
4848	    COMPILE(ret, "arsgpush head", node->nd_head);
4849	    ADD_INSN1(ret, line, splatarray, Qfalse);
4850	    ADD_INSN(ret, line, pop);
4851	    COMPILE_(ret, "argspush body", node->nd_body, poped);
4852	}
4853	else {
4854	    COMPILE(ret, "arsgpush head", node->nd_head);
4855	    COMPILE_(ret, "argspush body", node->nd_body, poped);
4856	    ADD_INSN1(ret, line, newarray, INT2FIX(1));
4857	    ADD_INSN(ret, line, concatarray);
4858	}
4859	break;
4860      }
4861      case NODE_SPLAT:{
4862	COMPILE(ret, "splat", node->nd_head);
4863	ADD_INSN1(ret, line, splatarray, Qtrue);
4864
4865	if (poped) {
4866	    ADD_INSN(ret, line, pop);
4867	}
4868	break;
4869      }
4870      case NODE_DEFN:{
4871	VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4872				    rb_str_dup(rb_id2str(node->nd_mid)),
4873				    ISEQ_TYPE_METHOD, line);
4874
4875	debugp_param("defn/iseq", iseqval);
4876
4877	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4878	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4879	ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
4880	ADD_INSN1(ret, line, putiseq, iseqval);
4881	ADD_SEND (ret, line, ID2SYM(id_core_define_method), INT2FIX(3));
4882
4883	if (poped) {
4884	    ADD_INSN(ret, line, pop);
4885	}
4886
4887	debugp_param("defn", iseqval);
4888	break;
4889      }
4890      case NODE_DEFS:{
4891	VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
4892				    rb_str_dup(rb_id2str(node->nd_mid)),
4893				    ISEQ_TYPE_METHOD, line);
4894
4895	debugp_param("defs/iseq", iseqval);
4896
4897	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4898	COMPILE(ret, "defs: recv", node->nd_recv);
4899	ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
4900	ADD_INSN1(ret, line, putiseq, iseqval);
4901	ADD_SEND (ret, line, ID2SYM(id_core_define_singleton_method), INT2FIX(3));
4902
4903	if (poped) {
4904	    ADD_INSN(ret, line, pop);
4905	}
4906	break;
4907      }
4908      case NODE_ALIAS:{
4909	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4910	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4911	COMPILE(ret, "alias arg1", node->u1.node);
4912	COMPILE(ret, "alias arg2", node->u2.node);
4913	ADD_SEND(ret, line, ID2SYM(id_core_set_method_alias), INT2FIX(3));
4914
4915	if (poped) {
4916	    ADD_INSN(ret, line, pop);
4917	}
4918	break;
4919      }
4920      case NODE_VALIAS:{
4921	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4922	ADD_INSN1(ret, line, putobject, ID2SYM(node->u1.id));
4923	ADD_INSN1(ret, line, putobject, ID2SYM(node->u2.id));
4924	ADD_SEND(ret, line, ID2SYM(id_core_set_variable_alias), INT2FIX(2));
4925
4926	if (poped) {
4927	    ADD_INSN(ret, line, pop);
4928	}
4929	break;
4930      }
4931      case NODE_UNDEF:{
4932	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4933	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4934	COMPILE(ret, "undef arg", node->u2.node);
4935	ADD_SEND(ret, line, ID2SYM(id_core_undef_method), INT2FIX(2));
4936
4937	if (poped) {
4938	    ADD_INSN(ret, line, pop);
4939	}
4940	break;
4941      }
4942      case NODE_CLASS:{
4943	VALUE iseqval =
4944	    NEW_CHILD_ISEQVAL(
4945		node->nd_body,
4946		rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4947		ISEQ_TYPE_CLASS, line);
4948	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
4949	int flags = VM_DEFINECLASS_TYPE_CLASS;
4950	if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
4951	if (node->nd_super) flags |= VM_DEFINECLASS_FLAG_HAS_SUPERCLASS;
4952	COMPILE(ret, "super", node->nd_super);
4953	ADD_INSN3(ret, line, defineclass,
4954		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
4955
4956	if (poped) {
4957	    ADD_INSN(ret, line, pop);
4958	}
4959	break;
4960      }
4961      case NODE_MODULE:{
4962	VALUE iseqval = NEW_CHILD_ISEQVAL(
4963	    node->nd_body,
4964	    rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
4965	    ISEQ_TYPE_CLASS, line);
4966
4967	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
4968	int flags = VM_DEFINECLASS_TYPE_MODULE;
4969	if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
4970	ADD_INSN (ret, line, putnil); /* dummy */
4971	ADD_INSN3(ret, line, defineclass,
4972		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
4973	if (poped) {
4974	    ADD_INSN(ret, line, pop);
4975	}
4976	break;
4977      }
4978      case NODE_SCLASS:{
4979	ID singletonclass;
4980	VALUE iseqval =
4981	    NEW_ISEQVAL(node->nd_body, rb_str_new2("singleton class"),
4982			ISEQ_TYPE_CLASS, line);
4983
4984	COMPILE(ret, "sclass#recv", node->nd_recv);
4985	ADD_INSN (ret, line, putnil);
4986	CONST_ID(singletonclass, "singletonclass");
4987	ADD_INSN3(ret, line, defineclass,
4988		  ID2SYM(singletonclass), iseqval,
4989		  INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
4990
4991	if (poped) {
4992	    ADD_INSN(ret, line, pop);
4993	}
4994	break;
4995      }
4996      case NODE_COLON2:{
4997	if (rb_is_const_id(node->nd_mid)) {
4998	    /* constant */
4999	    LABEL *lend = NEW_LABEL(line);
5000	    int ic_index = iseq->ic_size++;
5001
5002	    DECL_ANCHOR(pref);
5003	    DECL_ANCHOR(body);
5004
5005	    INIT_ANCHOR(pref);
5006	    INIT_ANCHOR(body);
5007	    compile_colon2(iseq, node, pref, body);
5008	    if (LIST_SIZE_ZERO(pref)) {
5009		if (iseq->compile_data->option->inline_const_cache) {
5010		    ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
5011		}
5012		else {
5013		    ADD_INSN(ret, line, putnil);
5014		}
5015
5016		ADD_SEQ(ret, body);
5017
5018		if (iseq->compile_data->option->inline_const_cache) {
5019		    ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
5020		    ADD_LABEL(ret, lend);
5021		}
5022	    }
5023	    else {
5024		ADD_SEQ(ret, pref);
5025		ADD_SEQ(ret, body);
5026	    }
5027	}
5028	else {
5029	    /* function call */
5030	    ADD_CALL_RECEIVER(ret, line);
5031	    COMPILE(ret, "colon2#nd_head", node->nd_head);
5032	    ADD_CALL(ret, line, ID2SYM(node->nd_mid),
5033		     INT2FIX(1));
5034	}
5035	if (poped) {
5036	    ADD_INSN(ret, line, pop);
5037	}
5038	break;
5039      }
5040      case NODE_COLON3:{
5041	LABEL *lend = NEW_LABEL(line);
5042	int ic_index = iseq->ic_size++;
5043
5044	debugi("colon3#nd_mid", node->nd_mid);
5045
5046	/* add cache insn */
5047	if (iseq->compile_data->option->inline_const_cache) {
5048	    ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
5049	    ADD_INSN(ret, line, pop);
5050	}
5051
5052	ADD_INSN1(ret, line, putobject, rb_cObject);
5053	ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
5054
5055	if (iseq->compile_data->option->inline_const_cache) {
5056	    ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
5057	    ADD_LABEL(ret, lend);
5058	}
5059
5060	if (poped) {
5061	    ADD_INSN(ret, line, pop);
5062	}
5063	break;
5064      }
5065      case NODE_DOT2:
5066      case NODE_DOT3:{
5067	VALUE flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
5068	COMPILE(ret, "min", (NODE *) node->nd_beg);
5069	COMPILE(ret, "max", (NODE *) node->nd_end);
5070	if (poped) {
5071	    ADD_INSN(ret, line, pop);
5072	    ADD_INSN(ret, line, pop);
5073	}
5074	else {
5075	    ADD_INSN1(ret, line, newrange, flag);
5076	}
5077	break;
5078      }
5079      case NODE_FLIP2:
5080      case NODE_FLIP3:{
5081	LABEL *lend = NEW_LABEL(line);
5082	LABEL *lfin = NEW_LABEL(line);
5083	LABEL *ltrue = NEW_LABEL(line);
5084	rb_iseq_t *local_iseq = iseq->local_iseq;
5085	rb_num_t cnt;
5086	VALUE key;
5087
5088	cnt = local_iseq->flip_cnt++ + DEFAULT_SPECIAL_VAR_COUNT;
5089	key = INT2FIX(cnt);
5090
5091	ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
5092	ADD_INSNL(ret, line, branchif, lend);
5093
5094	/* *flip == 0 */
5095	COMPILE(ret, "flip2 beg", node->nd_beg);
5096	ADD_INSN(ret, line, dup);
5097	ADD_INSNL(ret, line, branchunless, lfin);
5098	if (nd_type(node) == NODE_FLIP3) {
5099	    ADD_INSN(ret, line, dup);
5100	    ADD_INSN1(ret, line, setspecial, key);
5101	    ADD_INSNL(ret, line, jump, lfin);
5102	}
5103	else {
5104	    ADD_INSN1(ret, line, setspecial, key);
5105	}
5106
5107	/* *flip == 1 */
5108	ADD_LABEL(ret, lend);
5109	COMPILE(ret, "flip2 end", node->nd_end);
5110	ADD_INSNL(ret, line, branchunless, ltrue);
5111	ADD_INSN1(ret, line, putobject, Qfalse);
5112	ADD_INSN1(ret, line, setspecial, key);
5113
5114	ADD_LABEL(ret, ltrue);
5115	ADD_INSN1(ret, line, putobject, Qtrue);
5116
5117	ADD_LABEL(ret, lfin);
5118	break;
5119      }
5120      case NODE_SELF:{
5121	if (!poped) {
5122	    ADD_INSN(ret, line, putself);
5123	}
5124	break;
5125      }
5126      case NODE_NIL:{
5127	if (!poped) {
5128	    ADD_INSN(ret, line, putnil);
5129	}
5130	break;
5131      }
5132      case NODE_TRUE:{
5133	if (!poped) {
5134	    ADD_INSN1(ret, line, putobject, Qtrue);
5135	}
5136	break;
5137      }
5138      case NODE_FALSE:{
5139	if (!poped) {
5140	    ADD_INSN1(ret, line, putobject, Qfalse);
5141	}
5142	break;
5143      }
5144      case NODE_ERRINFO:{
5145	if (!poped) {
5146	    if (iseq->type == ISEQ_TYPE_RESCUE) {
5147		ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
5148	    }
5149	    else {
5150		rb_iseq_t *ip = iseq;
5151		int level = 0;
5152		while (ip) {
5153		    if (ip->type == ISEQ_TYPE_RESCUE) {
5154			break;
5155		    }
5156		    ip = ip->parent_iseq;
5157		    level++;
5158		}
5159		if (ip) {
5160		    ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(level));
5161		}
5162		else {
5163		    ADD_INSN(ret, line, putnil);
5164		}
5165	    }
5166	}
5167	break;
5168      }
5169      case NODE_DEFINED:{
5170	if (poped) break;
5171	if (!node->nd_head) {
5172	    VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5173	    ADD_INSN1(ret, nd_line(node), putobject, str);
5174	}
5175	else {
5176	    LABEL *lfinish[2];
5177	    lfinish[0] = NEW_LABEL(line);
5178	    lfinish[1] = 0;
5179	    ADD_INSN(ret, line, putnil);
5180	    defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
5181	    ADD_INSN(ret, line, swap);
5182	    ADD_INSN(ret, line, pop);
5183	    if (lfinish[1]) {
5184		ADD_LABEL(ret, lfinish[1]);
5185	    }
5186	    ADD_LABEL(ret, lfinish[0]);
5187	}
5188	break;
5189      }
5190      case NODE_POSTEXE:{
5191	LABEL *lend = NEW_LABEL(line);
5192	VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
5193	int ic_index = iseq->ic_size++;
5194
5195	ADD_INSN2(ret, line, onceinlinecache, lend, INT2FIX(ic_index));
5196	ADD_INSN(ret, line, pop);
5197
5198	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5199	ADD_INSN1(ret, line, putiseq, block);
5200	ADD_SEND (ret, line, ID2SYM(id_core_set_postexe), INT2FIX(1));
5201
5202	ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
5203	ADD_LABEL(ret, lend);
5204
5205	if (poped) {
5206	    ADD_INSN(ret, line, pop);
5207	}
5208	break;
5209      }
5210      case NODE_KW_ARG:{
5211	LABEL *default_label = NEW_LABEL(line);
5212	LABEL *end_label = NEW_LABEL(line);
5213	int idx, lv, ls;
5214	ID id = node->nd_body->nd_vid;
5215
5216	ADD_INSN(ret, line, dup);
5217	ADD_INSN1(ret, line, putobject, ID2SYM(id));
5218	ADD_SEND(ret, line, ID2SYM(rb_intern("key?")), INT2FIX(1));
5219	ADD_INSNL(ret, line, branchunless, default_label);
5220	ADD_INSN(ret, line, dup);
5221	ADD_INSN1(ret, line, putobject, ID2SYM(id));
5222	ADD_SEND(ret, line, ID2SYM(rb_intern("delete")), INT2FIX(1));
5223	switch (nd_type(node->nd_body)) {
5224	  case NODE_LASGN:
5225	    idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
5226	    ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
5227	    break;
5228	  case NODE_DASGN:
5229	  case NODE_DASGN_CURR:
5230	    idx = get_dyna_var_idx(iseq, id, &lv, &ls);
5231	    ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
5232	    break;
5233	  default:
5234	    rb_bug("iseq_compile_each (NODE_KW_ARG): unknown node: %s", ruby_node_name(nd_type(node->nd_body)));
5235	}
5236	ADD_INSNL(ret, line, jump, end_label);
5237	ADD_LABEL(ret, default_label);
5238	COMPILE_POPED(ret, "keyword default argument", node->nd_body);
5239	ADD_LABEL(ret, end_label);
5240	break;
5241      }
5242      case NODE_DSYM:{
5243	compile_dstr(iseq, ret, node);
5244	if (!poped) {
5245	    ADD_SEND(ret, line, ID2SYM(idIntern), INT2FIX(0));
5246	}
5247	else {
5248	    ADD_INSN(ret, line, pop);
5249	}
5250	break;
5251      }
5252      case NODE_ATTRASGN:{
5253	DECL_ANCHOR(recv);
5254	DECL_ANCHOR(args);
5255	VALUE flag = 0;
5256	VALUE argc;
5257
5258	INIT_ANCHOR(recv);
5259	INIT_ANCHOR(args);
5260	argc = setup_args(iseq, args, node->nd_args, &flag);
5261
5262	if (node->nd_recv == (NODE *) 1) {
5263	    flag |= VM_CALL_FCALL;
5264	    ADD_INSN(recv, line, putself);
5265	}
5266	else {
5267	    COMPILE(recv, "recv", node->nd_recv);
5268	}
5269
5270	debugp_param("argc", argc);
5271	debugp_param("nd_mid", ID2SYM(node->nd_mid));
5272
5273	if (!poped) {
5274	    ADD_INSN(ret, line, putnil);
5275	    ADD_SEQ(ret, recv);
5276	    ADD_SEQ(ret, args);
5277
5278	    if (flag & VM_CALL_ARGS_BLOCKARG) {
5279		ADD_INSN1(ret, line, topn, INT2FIX(1));
5280		if (flag & VM_CALL_ARGS_SPLAT) {
5281		    ADD_INSN1(ret, line, putobject, INT2FIX(-1));
5282		    ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
5283		}
5284		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
5285		ADD_INSN (ret, line, pop);
5286	    }
5287	    else if (flag & VM_CALL_ARGS_SPLAT) {
5288		ADD_INSN(ret, line, dup);
5289		ADD_INSN1(ret, line, putobject, INT2FIX(-1));
5290		ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
5291		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
5292		ADD_INSN (ret, line, pop);
5293	    }
5294	    else {
5295		ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
5296	    }
5297	}
5298	else {
5299	    ADD_SEQ(ret, recv);
5300	    ADD_SEQ(ret, args);
5301	}
5302	ADD_SEND_R(ret, line, ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
5303	ADD_INSN(ret, line, pop);
5304
5305	break;
5306      }
5307      case NODE_PRELUDE:{
5308	COMPILE_POPED(ret, "prelude", node->nd_head);
5309	COMPILE_(ret, "body", node->nd_body, poped);
5310	break;
5311      }
5312      case NODE_LAMBDA:{
5313	/* compile same as lambda{...} */
5314	VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
5315	VALUE argc = INT2FIX(0);
5316	ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5317	ADD_CALL_WITH_BLOCK(ret, line, ID2SYM(idLambda), argc, block);
5318
5319	if (poped) {
5320	    ADD_INSN(ret, line, pop);
5321	}
5322	break;
5323      }
5324      default:
5325	rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
5326	return COMPILE_NG;
5327    }
5328
5329    debug_node_end();
5330    return COMPILE_OK;
5331}
5332
5333/***************************/
5334/* instruction information */
5335/***************************/
5336
5337static int
5338insn_data_length(INSN *iobj)
5339{
5340    return insn_len(iobj->insn_id);
5341}
5342
5343static int
5344calc_sp_depth(int depth, INSN *insn)
5345{
5346    return insn_stack_increase(depth, insn->insn_id, insn->operands);
5347}
5348
5349static int
5350insn_data_line_no(INSN *iobj)
5351{
5352    return insn_len(iobj->line_no);
5353}
5354
5355static VALUE
5356insn_data_to_s_detail(INSN *iobj)
5357{
5358    VALUE str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
5359
5360    if (iobj->operands) {
5361	const char *types = insn_op_types(iobj->insn_id);
5362	int j;
5363
5364	for (j = 0; types[j]; j++) {
5365	    char type = types[j];
5366	    printf("str: %"PRIxVALUE", type: %c\n", str, type);
5367
5368	    switch (type) {
5369	      case TS_OFFSET:	/* label(destination position) */
5370		{
5371		    LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
5372		    rb_str_catf(str, "<L%03d>", lobj->label_no);
5373		    break;
5374		}
5375		break;
5376	      case TS_ISEQ:	/* iseq */
5377		{
5378		    rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
5379		    VALUE val = Qnil;
5380		    if (0 && iseq) { /* TODO: invalidate now */
5381			val = iseq->self;
5382		    }
5383		    rb_str_concat(str, rb_inspect(val));
5384		}
5385		break;
5386	      case TS_LINDEX:
5387	      case TS_NUM:	/* ulong */
5388	      case TS_VALUE:	/* VALUE */
5389		{
5390		    VALUE v = OPERAND_AT(iobj, j);
5391		    rb_str_concat(str, rb_inspect(v));
5392		    break;
5393		}
5394	      case TS_ID:	/* ID */
5395		rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
5396		break;
5397	      case TS_GENTRY:
5398		{
5399		    struct rb_global_entry *entry = (struct rb_global_entry *)
5400		      (OPERAND_AT(iobj, j) & (~1));
5401		    rb_str_cat2(str, rb_id2name(entry->id));
5402		    break;
5403		}
5404	      case TS_IC:	/* inline cache */
5405		rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
5406		break;
5407	      case TS_CALLINFO: /* call info */
5408		{
5409		    rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, j);
5410		    rb_str_catf(str, "<callinfo:%s, %d>", ci->mid ? rb_id2name(ci->mid) : "", ci->orig_argc);
5411		    break;
5412		}
5413	      case TS_CDHASH:	/* case/when condition cache */
5414		rb_str_cat2(str, "<ch>");
5415		break;
5416	      default:{
5417		rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
5418	      }
5419	    }
5420	    if (types[j + 1]) {
5421		rb_str_cat2(str, ", ");
5422	    }
5423	}
5424    }
5425    return str;
5426}
5427
5428static void
5429dump_disasm_list(struct iseq_link_element *link)
5430{
5431    int pos = 0;
5432    INSN *iobj;
5433    LABEL *lobj;
5434    VALUE str;
5435
5436    printf("-- raw disasm--------\n");
5437
5438    while (link) {
5439	switch (link->type) {
5440	  case ISEQ_ELEMENT_INSN:
5441	    {
5442		iobj = (INSN *)link;
5443		str = insn_data_to_s_detail(iobj);
5444		printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str), insn_data_line_no(iobj));
5445		pos += insn_data_length(iobj);
5446		break;
5447	    }
5448	  case ISEQ_ELEMENT_LABEL:
5449	    {
5450		lobj = (LABEL *)link;
5451		printf("<L%03d>\n", lobj->label_no);
5452		break;
5453	    }
5454	  case ISEQ_ELEMENT_NONE:
5455	    {
5456		printf("[none]\n");
5457		break;
5458	    }
5459	  case ISEQ_ELEMENT_ADJUST:
5460	    {
5461		ADJUST *adjust = (ADJUST *)link;
5462		printf("adjust: [label: %d]\n", adjust->label->label_no);
5463		break;
5464	    }
5465	  default:
5466	    /* ignore */
5467	    rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
5468	}
5469	link = link->next;
5470    }
5471    printf("---------------------\n");
5472}
5473
5474const char *
5475rb_insns_name(int i)
5476{
5477    return insn_name_info[i];
5478}
5479
5480VALUE
5481rb_insns_name_array(void)
5482{
5483    VALUE ary = rb_ary_new();
5484    int i;
5485    for (i = 0; i < numberof(insn_name_info); i++) {
5486	rb_ary_push(ary, rb_obj_freeze(rb_str_new2(insn_name_info[i])));
5487    }
5488    return rb_obj_freeze(ary);
5489}
5490
5491static LABEL *
5492register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
5493{
5494    LABEL *label = 0;
5495    st_data_t tmp;
5496    obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
5497
5498    if (st_lookup(labels_table, obj, &tmp) == 0) {
5499	label = NEW_LABEL(0);
5500	st_insert(labels_table, obj, (st_data_t)label);
5501    }
5502    else {
5503	label = (LABEL *)tmp;
5504    }
5505    return label;
5506}
5507
5508static VALUE
5509get_exception_sym2type(VALUE sym)
5510{
5511#undef rb_intern
5512#define rb_intern(str) rb_intern_const(str)
5513    VALUE sym_inspect;
5514    static VALUE symRescue, symEnsure, symRetry;
5515    static VALUE symBreak, symRedo, symNext;
5516
5517    if (symRescue == 0) {
5518	symRescue = ID2SYM(rb_intern("rescue"));
5519	symEnsure = ID2SYM(rb_intern("ensure"));
5520	symRetry  = ID2SYM(rb_intern("retry"));
5521	symBreak  = ID2SYM(rb_intern("break"));
5522	symRedo   = ID2SYM(rb_intern("redo"));
5523	symNext   = ID2SYM(rb_intern("next"));
5524    }
5525
5526    if (sym == symRescue) return CATCH_TYPE_RESCUE;
5527    if (sym == symEnsure) return CATCH_TYPE_ENSURE;
5528    if (sym == symRetry)  return CATCH_TYPE_RETRY;
5529    if (sym == symBreak)  return CATCH_TYPE_BREAK;
5530    if (sym == symRedo)   return CATCH_TYPE_REDO;
5531    if (sym == symNext)   return CATCH_TYPE_NEXT;
5532    sym_inspect = rb_inspect(sym);
5533    rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
5534	     StringValuePtr(sym_inspect));
5535    return 0;
5536}
5537
5538static int
5539iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
5540		     VALUE exception)
5541{
5542    int i;
5543
5544    for (i=0; i<RARRAY_LEN(exception); i++) {
5545	VALUE v, type, *ptr, eiseqval;
5546	LABEL *lstart, *lend, *lcont;
5547	int sp;
5548
5549	RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
5550					 "Array", "to_ary");
5551	if (RARRAY_LEN(v) != 6) {
5552	    rb_raise(rb_eSyntaxError, "wrong exception entry");
5553	}
5554	ptr  = RARRAY_PTR(v);
5555	type = get_exception_sym2type(ptr[0]);
5556	if (ptr[1] == Qnil) {
5557	    eiseqval = 0;
5558	}
5559	else {
5560	    eiseqval = rb_iseq_load(ptr[1], iseq->self, Qnil);
5561	}
5562
5563	lstart = register_label(iseq, labels_table, ptr[2]);
5564	lend   = register_label(iseq, labels_table, ptr[3]);
5565	lcont  = register_label(iseq, labels_table, ptr[4]);
5566	sp     = NUM2INT(ptr[5]);
5567
5568	(void)sp;
5569
5570	ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
5571    }
5572    return COMPILE_OK;
5573}
5574
5575static struct st_table *
5576insn_make_insn_table(void)
5577{
5578    struct st_table *table;
5579    int i;
5580    table = st_init_numtable();
5581
5582    for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
5583	st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
5584    }
5585
5586    return table;
5587}
5588
5589static VALUE
5590iseq_build_load_iseq(rb_iseq_t *iseq, VALUE op)
5591{
5592    VALUE iseqval;
5593    if (RB_TYPE_P(op, T_ARRAY)) {
5594	iseqval = rb_iseq_load(op, iseq->self, Qnil);
5595    }
5596    else if (CLASS_OF(op) == rb_cISeq) {
5597	iseqval = op;
5598    }
5599    else {
5600	rb_raise(rb_eSyntaxError, "ISEQ is required");
5601    }
5602    iseq_add_mark_object(iseq, iseqval);
5603    return iseqval;
5604}
5605
5606static int
5607iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
5608		VALUE body, struct st_table *labels_table)
5609{
5610    /* TODO: body should be frozen */
5611    VALUE *ptr = RARRAY_PTR(body);
5612    long i, len = RARRAY_LEN(body);
5613    int j;
5614    int line_no = 0;
5615
5616    /*
5617     * index -> LABEL *label
5618     */
5619    static struct st_table *insn_table;
5620
5621    if (insn_table == 0) {
5622	insn_table = insn_make_insn_table();
5623    }
5624
5625    for (i=0; i<len; i++) {
5626	VALUE obj = ptr[i];
5627
5628	if (SYMBOL_P(obj)) {
5629	    LABEL *label = register_label(iseq, labels_table, obj);
5630	    ADD_LABEL(anchor, label);
5631	}
5632	else if (FIXNUM_P(obj)) {
5633	    line_no = NUM2INT(obj);
5634	}
5635	else if (RB_TYPE_P(obj, T_ARRAY)) {
5636	    VALUE *argv = 0;
5637	    int argc = RARRAY_LENINT(obj) - 1;
5638	    st_data_t insn_id;
5639	    VALUE insn;
5640
5641	    insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
5642	    if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
5643		/* TODO: exception */
5644		RB_GC_GUARD(insn) = rb_inspect(insn);
5645		rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
5646				 "unknown instruction: %s", RSTRING_PTR(insn));
5647	    }
5648
5649	    if (argc != insn_len((VALUE)insn_id)-1) {
5650		rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
5651				 "operand size mismatch");
5652	    }
5653
5654	    if (argc > 0) {
5655		argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
5656		for (j=0; j<argc; j++) {
5657		    VALUE op = rb_ary_entry(obj, j+1);
5658		    switch (insn_op_type((VALUE)insn_id, j)) {
5659		      case TS_OFFSET: {
5660			LABEL *label = register_label(iseq, labels_table, op);
5661			argv[j] = (VALUE)label;
5662			break;
5663		      }
5664		      case TS_LINDEX:
5665		      case TS_NUM:
5666			(void)NUM2INT(op);
5667			argv[j] = op;
5668			break;
5669		      case TS_VALUE:
5670			argv[j] = op;
5671			iseq_add_mark_object(iseq, op);
5672			break;
5673		      case TS_ISEQ:
5674			{
5675			    if (op != Qnil) {
5676				argv[j] = iseq_build_load_iseq(iseq, op);
5677			    }
5678			    else {
5679				argv[j] = 0;
5680			    }
5681			}
5682			break;
5683		      case TS_GENTRY:
5684			op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
5685			argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
5686			break;
5687		      case TS_IC:
5688			argv[j] = op;
5689			if (NUM2INT(op) >= iseq->ic_size) {
5690			    iseq->ic_size = NUM2INT(op) + 1;
5691			}
5692			break;
5693		      case TS_CALLINFO:
5694			{
5695			    ID mid = 0;
5696			    int orig_argc = 0;
5697			    VALUE block = 0;
5698			    unsigned long flag = 0;
5699
5700			    if (!NIL_P(op)) {
5701				VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
5702				VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
5703				VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
5704				VALUE vblock = rb_hash_aref(op, ID2SYM(rb_intern("blockptr")));
5705
5706				if (!NIL_P(vmid)) mid = SYM2ID(vmid);
5707				if (!NIL_P(vflag)) flag = NUM2ULONG(vflag);
5708				if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
5709				if (!NIL_P(vblock)) block = iseq_build_load_iseq(iseq, vblock);
5710			    }
5711			    argv[j] = (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag);
5712			}
5713			break;
5714		      case TS_ID:
5715			argv[j] = rb_convert_type(op, T_SYMBOL,
5716						  "Symbol", "to_sym");
5717			break;
5718		      case TS_CDHASH:
5719			{
5720			    int i;
5721			    op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
5722			    op = rb_ary_dup(op);
5723			    for (i=0; i<RARRAY_LEN(op); i+=2) {
5724				VALUE sym = rb_ary_entry(op, i+1);
5725				LABEL *label =
5726				  register_label(iseq, labels_table, sym);
5727				rb_ary_store(op, i+1, (VALUE)label | 1);
5728			    }
5729			    argv[j] = op;
5730			    iseq_add_mark_object_compile_time(iseq, op);
5731			}
5732			break;
5733		      default:
5734			rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
5735		    }
5736		}
5737	    }
5738	    ADD_ELEM(anchor,
5739		     (LINK_ELEMENT*)new_insn_core(iseq, line_no,
5740						  (enum ruby_vminsn_type)insn_id, argc, argv));
5741	}
5742	else {
5743	    rb_raise(rb_eTypeError, "unexpected object for instruction");
5744	}
5745    }
5746    validate_labels(iseq, labels_table);
5747    st_free_table(labels_table);
5748    iseq_setup(iseq, anchor);
5749    return COMPILE_OK;
5750}
5751
5752#define CHECK_ARRAY(v)   rb_convert_type((v), T_ARRAY, "Array", "to_ary")
5753#define CHECK_STRING(v)  rb_convert_type((v), T_STRING, "String", "to_str")
5754#define CHECK_SYMBOL(v)  rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
5755static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
5756
5757VALUE
5758rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
5759			 VALUE exception, VALUE body)
5760{
5761    int i;
5762    ID *tbl;
5763    struct st_table *labels_table = st_init_numtable();
5764    DECL_ANCHOR(anchor);
5765    INIT_ANCHOR(anchor);
5766
5767    iseq->local_table_size = RARRAY_LENINT(locals);
5768    iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
5769    iseq->local_size = iseq->local_table_size + 1;
5770
5771    for (i=0; i<RARRAY_LEN(locals); i++) {
5772	VALUE lv = RARRAY_PTR(locals)[i];
5773	tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
5774    }
5775
5776    /* args */
5777    if (FIXNUM_P(args)) {
5778	iseq->arg_size = iseq->argc = FIX2INT(args);
5779	iseq->arg_simple = 1;
5780    }
5781    else {
5782	int i = 0;
5783	VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
5784	VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
5785	VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
5786	VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
5787	VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
5788	VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
5789	VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
5790
5791	iseq->argc = FIX2INT(argc);
5792	iseq->arg_rest = FIX2INT(arg_rest);
5793	iseq->arg_post_len = FIX2INT(arg_post_len);
5794	iseq->arg_post_start = FIX2INT(arg_post_start);
5795	iseq->arg_block = FIX2INT(arg_block);
5796	iseq->arg_opts = RARRAY_LENINT(arg_opt_labels);
5797	iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
5798
5799	if (iseq->arg_block != -1) {
5800	    iseq->arg_size = iseq->arg_block + 1;
5801	}
5802	else if (iseq->arg_post_len) {
5803	    iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
5804	}
5805	else if (iseq->arg_rest != -1) {
5806	    iseq->arg_size = iseq->arg_rest + 1;
5807	}
5808	else {
5809	    iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
5810	}
5811
5812	for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
5813	    iseq->arg_opt_table[i] =
5814	      (VALUE)register_label(iseq, labels_table,
5815				    rb_ary_entry(arg_opt_labels, i));
5816	}
5817
5818	iseq->arg_simple = NUM2INT(arg_simple);
5819    }
5820
5821    /* exception */
5822    iseq_build_from_ary_exception(iseq, labels_table, exception);
5823
5824    /* body */
5825    iseq_build_from_ary_body(iseq, anchor, body, labels_table);
5826    return iseq->self;
5827}
5828
5829/* for parser */
5830
5831int
5832rb_dvar_defined(ID id)
5833{
5834    rb_thread_t *th = GET_THREAD();
5835    rb_iseq_t *iseq;
5836    if (th->base_block && (iseq = th->base_block->iseq)) {
5837	while (iseq->type == ISEQ_TYPE_BLOCK ||
5838	       iseq->type == ISEQ_TYPE_RESCUE ||
5839	       iseq->type == ISEQ_TYPE_ENSURE ||
5840	       iseq->type == ISEQ_TYPE_EVAL ||
5841	       iseq->type == ISEQ_TYPE_MAIN
5842	       ) {
5843	    int i;
5844
5845	    for (i = 0; i < iseq->local_table_size; i++) {
5846		if (iseq->local_table[i] == id) {
5847		    return 1;
5848		}
5849	    }
5850	    iseq = iseq->parent_iseq;
5851	}
5852    }
5853    return 0;
5854}
5855
5856int
5857rb_local_defined(ID id)
5858{
5859    rb_thread_t *th = GET_THREAD();
5860    rb_iseq_t *iseq;
5861
5862    if (th->base_block && th->base_block->iseq) {
5863	int i;
5864	iseq = th->base_block->iseq->local_iseq;
5865
5866	for (i=0; i<iseq->local_table_size; i++) {
5867	    if (iseq->local_table[i] == id) {
5868		return 1;
5869	    }
5870	}
5871    }
5872    return 0;
5873}
5874
5875int
5876rb_parse_in_eval(void)
5877{
5878    return GET_THREAD()->parse_in_eval > 0;
5879}
5880
5881int
5882rb_parse_in_main(void)
5883{
5884    return GET_THREAD()->parse_in_eval < 0;
5885}
5886