Ruby  2.0.0p247(2013-06-27revision41674)
compile.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   compile.c - ruby node tree -> VM instruction sequence
00004 
00005   $Author: nagachika $
00006   created at: 04/01/01 03:42:15 JST
00007 
00008   Copyright (C) 2004-2007 Koichi Sasada
00009 
00010 **********************************************************************/
00011 
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include <math.h>
00015 
00016 #define USE_INSN_STACK_INCREASE 1
00017 #include "vm_core.h"
00018 #include "iseq.h"
00019 #include "insns.inc"
00020 #include "insns_info.inc"
00021 
00022 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00023 #define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
00024 #define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
00025 
00026 typedef struct iseq_link_element {
00027     enum {
00028         ISEQ_ELEMENT_NONE,
00029         ISEQ_ELEMENT_LABEL,
00030         ISEQ_ELEMENT_INSN,
00031         ISEQ_ELEMENT_ADJUST
00032     } type;
00033     struct iseq_link_element *next;
00034     struct iseq_link_element *prev;
00035 } LINK_ELEMENT;
00036 
00037 typedef struct iseq_link_anchor {
00038     LINK_ELEMENT anchor;
00039     LINK_ELEMENT *last;
00040 } LINK_ANCHOR;
00041 
00042 typedef struct iseq_label_data {
00043     LINK_ELEMENT link;
00044     int label_no;
00045     int position;
00046     int sc_state;
00047     int set;
00048     int sp;
00049 } LABEL;
00050 
00051 typedef struct iseq_insn_data {
00052     LINK_ELEMENT link;
00053     enum ruby_vminsn_type insn_id;
00054     unsigned int line_no;
00055     int operand_size;
00056     int sc_state;
00057     VALUE *operands;
00058 } INSN;
00059 
00060 typedef struct iseq_adjust_data {
00061     LINK_ELEMENT link;
00062     LABEL *label;
00063     int line_no;
00064 } ADJUST;
00065 
00066 struct ensure_range {
00067     LABEL *begin;
00068     LABEL *end;
00069     struct ensure_range *next;
00070 };
00071 
00072 struct iseq_compile_data_ensure_node_stack {
00073     NODE *ensure_node;
00074     struct iseq_compile_data_ensure_node_stack *prev;
00075     struct ensure_range *erange;
00076 };
00077 
00091 #ifndef CPDEBUG
00092 #define CPDEBUG 0
00093 #endif
00094 
00095 #if CPDEBUG >= 0
00096 #define compile_debug CPDEBUG
00097 #else
00098 #define compile_debug iseq->compile_data->option->debug_level
00099 #endif
00100 
00101 #if CPDEBUG
00102 
00103 #define compile_debug_print_indent(level) \
00104     ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
00105 
00106 #define debugp(header, value) (void) \
00107   (compile_debug_print_indent(1) && \
00108    ruby_debug_print_value(1, compile_debug, (header), (value)))
00109 
00110 #define debugi(header, id)  (void) \
00111   (compile_debug_print_indent(1) && \
00112    ruby_debug_print_id(1, compile_debug, (header), (id)))
00113 
00114 #define debugp_param(header, value)  (void) \
00115   (compile_debug_print_indent(1) && \
00116    ruby_debug_print_value(1, compile_debug, (header), (value)))
00117 
00118 #define debugp_verbose(header, value)  (void) \
00119   (compile_debug_print_indent(2) && \
00120    ruby_debug_print_value(2, compile_debug, (header), (value)))
00121 
00122 #define debugp_verbose_node(header, value)  (void) \
00123   (compile_debug_print_indent(10) && \
00124    ruby_debug_print_value(10, compile_debug, (header), (value)))
00125 
00126 #define debug_node_start(node)  ((void) \
00127   (compile_debug_print_indent(1) && \
00128    (ruby_debug_print_node(1, CPDEBUG, "", (NODE *)(node)), gl_node_level)), \
00129    gl_node_level++)
00130 
00131 #define debug_node_end()  gl_node_level --
00132 
00133 #else
00134 
00135 static inline ID
00136 r_id(ID id)
00137 {
00138     return id;
00139 }
00140 
00141 static inline VALUE
00142 r_value(VALUE value)
00143 {
00144     return value;
00145 }
00146 
00147 #define debugi(header, id)                 r_id(id)
00148 #define debugp(header, value)              r_value(value)
00149 #define debugp_verbose(header, value)      r_value(value)
00150 #define debugp_verbose_node(header, value) r_value(value)
00151 #define debugp_param(header, value)        r_value(value)
00152 #define debug_node_start(node)             ((void)0)
00153 #define debug_node_end()                   ((void)0)
00154 #endif
00155 
00156 #if CPDEBUG > 1 || CPDEBUG < 0
00157 #define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
00158 #define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
00159 #else
00160 #define debugs                             if(0)printf
00161 #define debug_compile(msg, v) (v)
00162 #endif
00163 
00164 
00165 /* create new label */
00166 #define NEW_LABEL(l) new_label_body(iseq, (l))
00167 
00168 #define iseq_path(iseq) \
00169   (((rb_iseq_t*)DATA_PTR(iseq))->location.path)
00170 
00171 #define iseq_absolute_path(iseq) \
00172   (((rb_iseq_t*)DATA_PTR(iseq))->location.absolute_path)
00173 
00174 #define NEW_ISEQVAL(node, name, type, line_no)       \
00175   new_child_iseq(iseq, (node), (name), 0, (type), (line_no))
00176 
00177 #define NEW_CHILD_ISEQVAL(node, name, type, line_no)       \
00178   new_child_iseq(iseq, (node), (name), iseq->self, (type), (line_no))
00179 
00180 /* add instructions */
00181 #define ADD_SEQ(seq1, seq2) \
00182   APPEND_LIST((seq1), (seq2))
00183 
00184 /* add an instruction */
00185 #define ADD_INSN(seq, line, insn) \
00186   ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
00187 
00188 /* add an instruction with some operands (1, 2, 3, 5) */
00189 #define ADD_INSN1(seq, line, insn, op1) \
00190   ADD_ELEM((seq), (LINK_ELEMENT *) \
00191            new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
00192 
00193 /* add an instruction with label operand (alias of ADD_INSN1) */
00194 #define ADD_INSNL(seq, line, insn, label) ADD_INSN1(seq, line, insn, label)
00195 
00196 #define ADD_INSN2(seq, line, insn, op1, op2) \
00197   ADD_ELEM((seq), (LINK_ELEMENT *) \
00198            new_insn_body(iseq, (line), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
00199 
00200 #define ADD_INSN3(seq, line, insn, op1, op2, op3) \
00201   ADD_ELEM((seq), (LINK_ELEMENT *) \
00202            new_insn_body(iseq, (line), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
00203 
00204 /* Specific Insn factory */
00205 #define ADD_SEND(seq, line, id, argc) \
00206   ADD_SEND_R((seq), (line), (id), (argc), (VALUE)Qfalse, (VALUE)INT2FIX(0))
00207 
00208 #define ADD_CALL_RECEIVER(seq, line) \
00209   ADD_INSN((seq), (line), putself)
00210 
00211 #define ADD_CALL(seq, line, id, argc) \
00212   ADD_SEND_R((seq), (line), (id), (argc), (VALUE)Qfalse, (VALUE)INT2FIX(VM_CALL_FCALL))
00213 
00214 #define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block) \
00215   ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL))
00216 
00217 #define ADD_SEND_R(seq, line, id, argc, block, flag) \
00218   ADD_ELEM((seq), (LINK_ELEMENT *) \
00219            new_insn_send(iseq, (line), \
00220                          (VALUE)(id), (VALUE)(argc), (VALUE)(block), (VALUE)(flag)))
00221 
00222 #define ADD_TRACE(seq, line, event) \
00223   do { \
00224       if ((event) == RUBY_EVENT_LINE && iseq->coverage && \
00225           (line) != iseq->compile_data->last_coverable_line) { \
00226           RARRAY_PTR(iseq->coverage)[(line) - 1] = INT2FIX(0); \
00227           iseq->compile_data->last_coverable_line = (line); \
00228           ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_COVERAGE)); \
00229       } \
00230       if (iseq->compile_data->option->trace_instruction) { \
00231           ADD_INSN1((seq), (line), trace, INT2FIX(event)); \
00232       } \
00233   } while (0)
00234 
00235 /* add label */
00236 #define ADD_LABEL(seq, label) \
00237   ADD_ELEM((seq), (LINK_ELEMENT *) (label))
00238 
00239 #define APPEND_LABEL(seq, before, label) \
00240   APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
00241 
00242 #define ADD_ADJUST(seq, line, label) \
00243   ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line)))
00244 
00245 #define ADD_ADJUST_RESTORE(seq, label) \
00246   ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
00247 
00248 #define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)                \
00249     (rb_ary_push(iseq->compile_data->catch_table_ary,           \
00250                  rb_ary_new3(5, (type),                         \
00251                              (VALUE)(ls) | 1, (VALUE)(le) | 1,  \
00252                              (VALUE)(iseqv), (VALUE)(lc) | 1)))
00253 
00254 /* compile node */
00255 #define COMPILE(anchor, desc, node) \
00256   (debug_compile("== " desc "\n", \
00257                  iseq_compile_each(iseq, (anchor), (node), 0)))
00258 
00259 /* compile node, this node's value will be popped */
00260 #define COMPILE_POPED(anchor, desc, node)    \
00261   (debug_compile("== " desc "\n", \
00262                  iseq_compile_each(iseq, (anchor), (node), 1)))
00263 
00264 /* compile node, which is popped when 'poped' is true */
00265 #define COMPILE_(anchor, desc, node, poped)  \
00266   (debug_compile("== " desc "\n", \
00267                  iseq_compile_each(iseq, (anchor), (node), (poped))))
00268 
00269 #define OPERAND_AT(insn, idx) \
00270   (((INSN*)(insn))->operands[(idx)])
00271 
00272 #define INSN_OF(insn) \
00273   (((INSN*)(insn))->insn_id)
00274 
00275 /* error */
00276 #define COMPILE_ERROR(strs)                        \
00277 {                                                  \
00278   VALUE tmp = GET_THREAD()->errinfo;               \
00279   if (compile_debug) rb_compile_bug strs;          \
00280   GET_THREAD()->errinfo = iseq->compile_data->err_info;  \
00281   rb_compile_error strs;                           \
00282   iseq->compile_data->err_info = GET_THREAD()->errinfo; \
00283   GET_THREAD()->errinfo = tmp;                     \
00284   ret = 0;                                         \
00285   break;                                           \
00286 }
00287 
00288 #define ERROR_ARGS ruby_sourcefile, nd_line(node),
00289 
00290 
00291 #define COMPILE_OK 1
00292 #define COMPILE_NG 0
00293 
00294 
00295 /* leave name uninitialized so that compiler warn if INIT_ANCHOR is
00296  * missing */
00297 #define DECL_ANCHOR(name) \
00298   LINK_ANCHOR *name, name##_body__ = {{0,},}
00299 #define INIT_ANCHOR(name) \
00300   (name##_body__.last = &name##_body__.anchor, name = &name##_body__)
00301 
00302 #define hide_obj(obj) do {OBJ_FREEZE(obj); RBASIC(obj)->klass = 0;} while (0)
00303 
00304 #include "optinsn.inc"
00305 #if OPT_INSTRUCTIONS_UNIFICATION
00306 #include "optunifs.inc"
00307 #endif
00308 
00309 /* for debug */
00310 #if CPDEBUG < 0
00311 #define ISEQ_ARG iseq,
00312 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
00313 #else
00314 #define ISEQ_ARG
00315 #define ISEQ_ARG_DECLARE
00316 #endif
00317 
00318 #if CPDEBUG
00319 #define gl_node_level iseq->compile_data->node_level
00320 #if 0
00321 static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor);
00322 #endif
00323 #endif
00324 
00325 static void dump_disasm_list(LINK_ELEMENT *elem);
00326 
00327 static int insn_data_length(INSN *iobj);
00328 static int insn_data_line_no(INSN *iobj);
00329 static int calc_sp_depth(int depth, INSN *iobj);
00330 
00331 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...);
00332 static LABEL *new_label_body(rb_iseq_t *iseq, long line);
00333 static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
00334 
00335 static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int);
00336 static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
00337 static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
00338 static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
00339 
00340 static int iseq_set_local_table(rb_iseq_t *iseq, ID *tbl);
00341 static int iseq_set_exception_local_table(rb_iseq_t *iseq);
00342 static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node);
00343 
00344 static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
00345 static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
00346 static int iseq_set_exception_table(rb_iseq_t *iseq);
00347 static int iseq_set_optargs_table(rb_iseq_t *iseq);
00348 
00349 /*
00350  * To make Array to LinkedList, use link_anchor
00351  */
00352 
00353 static void
00354 verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *anchor)
00355 {
00356 #if CPDEBUG
00357     int flag = 0;
00358     LINK_ELEMENT *list, *plist;
00359 
00360     if (!compile_debug) return;
00361 
00362     list = anchor->anchor.next;
00363     plist = &anchor->anchor;
00364     while (list) {
00365         if (plist != list->prev) {
00366             flag += 1;
00367         }
00368         plist = list;
00369         list = list->next;
00370     }
00371 
00372     if (anchor->last != plist && anchor->last != 0) {
00373         flag |= 0x70000;
00374     }
00375 
00376     if (flag != 0) {
00377         rb_bug("list verify error: %08x (%s)", flag, info);
00378     }
00379 #endif
00380 }
00381 #if CPDEBUG < 0
00382 #define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
00383 #endif
00384 
00385 /*
00386  * elem1, elem2 => elem1, elem2, elem
00387  */
00388 static void
00389 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
00390 {
00391     elem->prev = anchor->last;
00392     anchor->last->next = elem;
00393     anchor->last = elem;
00394     verify_list("add", anchor);
00395 }
00396 
00397 /*
00398  * elem1, before, elem2 => elem1, before, elem, elem2
00399  */
00400 static void
00401 APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
00402 {
00403     elem->prev = before;
00404     elem->next = before->next;
00405     elem->next->prev = elem;
00406     before->next = elem;
00407     if (before == anchor->last) anchor->last = elem;
00408     verify_list("add", anchor);
00409 }
00410 #if CPDEBUG < 0
00411 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
00412 #define APPEND_ELEM(anchor, before, elem) ADD_ELEM(iseq, (anchor), (before), (elem))
00413 #endif
00414 
00415 static int
00416 iseq_add_mark_object(rb_iseq_t *iseq, VALUE v)
00417 {
00418     if (!SPECIAL_CONST_P(v)) {
00419         rb_ary_push(iseq->mark_ary, v);
00420     }
00421     return COMPILE_OK;
00422 }
00423 
00424 #define ruby_sourcefile         RSTRING_PTR(iseq->location.path)
00425 
00426 static int
00427 iseq_add_mark_object_compile_time(rb_iseq_t *iseq, VALUE v)
00428 {
00429     if (!SPECIAL_CONST_P(v)) {
00430         rb_ary_push(iseq->compile_data->mark_ary, v);
00431     }
00432     return COMPILE_OK;
00433 }
00434 
00435 static int
00436 validate_label(st_data_t name, st_data_t label, st_data_t arg)
00437 {
00438     rb_iseq_t *iseq = (rb_iseq_t *)arg;
00439     LABEL *lobj = (LABEL *)label;
00440     if (!lobj->link.next) {
00441         do {
00442             int ret;
00443             COMPILE_ERROR((ruby_sourcefile, lobj->position,
00444                            "%s: undefined label", rb_id2name((ID)name)));
00445             if (ret) break;
00446         } while (0);
00447     }
00448     return ST_CONTINUE;
00449 }
00450 
00451 static void
00452 validate_labels(rb_iseq_t *iseq, st_table *labels_table)
00453 {
00454     st_foreach(labels_table, validate_label, (st_data_t)iseq);
00455     if (!NIL_P(iseq->compile_data->err_info)) {
00456         rb_exc_raise(iseq->compile_data->err_info);
00457     }
00458 }
00459 
00460 VALUE
00461 rb_iseq_compile_node(VALUE self, NODE *node)
00462 {
00463     DECL_ANCHOR(ret);
00464     rb_iseq_t *iseq;
00465     INIT_ANCHOR(ret);
00466     GetISeqPtr(self, iseq);
00467 
00468     if (node == 0) {
00469         COMPILE(ret, "nil", node);
00470         iseq_set_local_table(iseq, 0);
00471     }
00472     else if (nd_type(node) == NODE_SCOPE) {
00473         /* iseq type of top, method, class, block */
00474         iseq_set_local_table(iseq, node->nd_tbl);
00475         iseq_set_arguments(iseq, ret, node->nd_args);
00476 
00477         switch (iseq->type) {
00478           case ISEQ_TYPE_BLOCK:
00479             {
00480                 LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
00481                 LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
00482 
00483                 ADD_LABEL(ret, start);
00484                 ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_B_CALL);
00485                 COMPILE(ret, "block body", node->nd_body);
00486                 ADD_LABEL(ret, end);
00487                 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_B_RETURN);
00488 
00489                 /* wide range catch handler must put at last */
00490                 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
00491                 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
00492                 break;
00493             }
00494           case ISEQ_TYPE_CLASS:
00495             {
00496                 ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
00497                 COMPILE(ret, "scoped node", node->nd_body);
00498                 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
00499                 break;
00500             }
00501           case ISEQ_TYPE_METHOD:
00502             {
00503                 ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
00504                 COMPILE(ret, "scoped node", node->nd_body);
00505                 ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
00506                 break;
00507             }
00508           default: {
00509             COMPILE(ret, "scoped node", node->nd_body);
00510             break;
00511           }
00512         }
00513     }
00514     else {
00515         switch (iseq->type) {
00516           case ISEQ_TYPE_METHOD:
00517           case ISEQ_TYPE_CLASS:
00518           case ISEQ_TYPE_BLOCK:
00519           case ISEQ_TYPE_EVAL:
00520           case ISEQ_TYPE_MAIN:
00521           case ISEQ_TYPE_TOP:
00522             rb_compile_error(ERROR_ARGS "compile/should not be reached: %s:%d",
00523                              __FILE__, __LINE__);
00524             break;
00525           case ISEQ_TYPE_RESCUE:
00526             iseq_set_exception_local_table(iseq);
00527             COMPILE(ret, "rescue", node);
00528             break;
00529           case ISEQ_TYPE_ENSURE:
00530             iseq_set_exception_local_table(iseq);
00531             COMPILE_POPED(ret, "ensure", node);
00532             break;
00533           case ISEQ_TYPE_DEFINED_GUARD:
00534             iseq_set_local_table(iseq, 0);
00535             COMPILE(ret, "defined guard", node);
00536             break;
00537           default:
00538             rb_bug("unknown scope");
00539         }
00540     }
00541 
00542     if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) {
00543         ADD_INSN2(ret, 0, getlocal, INT2FIX(2), INT2FIX(0));
00544         ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
00545     }
00546     else {
00547         ADD_INSN(ret, iseq->compile_data->last_line, leave);
00548     }
00549 
00550 #if SUPPORT_JOKE
00551     if (iseq->compile_data->labels_table) {
00552         validate_labels(iseq, iseq->compile_data->labels_table);
00553     }
00554 #endif
00555     return iseq_setup(iseq, ret);
00556 }
00557 
00558 int
00559 rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
00560 {
00561 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
00562     const void * const *table = rb_vm_get_insns_address_table();
00563     unsigned long i;
00564 
00565     iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size);
00566     MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size);
00567 
00568     for (i = 0; i < iseq->iseq_size; /* */ ) {
00569         int insn = (int)iseq->iseq_encoded[i];
00570         int len = insn_len(insn);
00571         iseq->iseq_encoded[i] = (VALUE)table[insn];
00572         i += len;
00573     }
00574 #else
00575     iseq->iseq_encoded = iseq->iseq;
00576 #endif
00577     return COMPILE_OK;
00578 }
00579 
00580 /*********************************************/
00581 /* definition of data structure for compiler */
00582 /*********************************************/
00583 
00584 static void *
00585 compile_data_alloc(rb_iseq_t *iseq, size_t size)
00586 {
00587     void *ptr = 0;
00588     struct iseq_compile_data_storage *storage =
00589         iseq->compile_data->storage_current;
00590 
00591     if (storage->pos + size > storage->size) {
00592         unsigned long alloc_size = storage->size * 2;
00593 
00594       retry:
00595         if (alloc_size < size) {
00596             alloc_size *= 2;
00597             goto retry;
00598         }
00599         storage->next = (void *)ALLOC_N(char, alloc_size +
00600                                         sizeof(struct
00601                                                iseq_compile_data_storage));
00602         storage = iseq->compile_data->storage_current = storage->next;
00603         storage->next = 0;
00604         storage->pos = 0;
00605         storage->size = alloc_size;
00606         storage->buff = (char *)(&storage->buff + 1);
00607     }
00608 
00609     ptr = (void *)&storage->buff[storage->pos];
00610     storage->pos += size;
00611     return ptr;
00612 }
00613 
00614 static INSN *
00615 compile_data_alloc_insn(rb_iseq_t *iseq)
00616 {
00617     return (INSN *)compile_data_alloc(iseq, sizeof(INSN));
00618 }
00619 
00620 static LABEL *
00621 compile_data_alloc_label(rb_iseq_t *iseq)
00622 {
00623     return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
00624 }
00625 
00626 static ADJUST *
00627 compile_data_alloc_adjust(rb_iseq_t *iseq)
00628 {
00629     return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
00630 }
00631 
00632 /*
00633  * elem1, elemX => elem1, elem2, elemX
00634  */
00635 static void
00636 INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
00637 {
00638     elem2->next = elem1->next;
00639     elem2->prev = elem1;
00640     elem1->next = elem2;
00641     if (elem2->next) {
00642         elem2->next->prev = elem2;
00643     }
00644 }
00645 
00646 #if 0 /* unused */
00647 /*
00648  * elemX, elem1 => elemX, elem2, elem1
00649  */
00650 static void
00651 INSERT_ELEM_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
00652 {
00653     elem2->prev = elem1->prev;
00654     elem2->next = elem1;
00655     elem1->prev = elem2;
00656     if (elem2->prev) {
00657         elem2->prev->next = elem2;
00658     }
00659 }
00660 #endif
00661 
00662 /*
00663  * elemX, elem1, elemY => elemX, elem2, elemY
00664  */
00665 static void
00666 REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
00667 {
00668     elem2->prev = elem1->prev;
00669     elem2->next = elem1->next;
00670     if (elem1->prev) {
00671         elem1->prev->next = elem2;
00672     }
00673     if (elem1->next) {
00674         elem1->next->prev = elem2;
00675     }
00676 }
00677 
00678 static void
00679 REMOVE_ELEM(LINK_ELEMENT *elem)
00680 {
00681     elem->prev->next = elem->next;
00682     if (elem->next) {
00683         elem->next->prev = elem->prev;
00684     }
00685 }
00686 
00687 static LINK_ELEMENT *
00688 FIRST_ELEMENT(LINK_ANCHOR *anchor)
00689 {
00690     return anchor->anchor.next;
00691 }
00692 
00693 #if 0 /* unused */
00694 static LINK_ELEMENT *
00695 LAST_ELEMENT(LINK_ANCHOR *anchor)
00696 {
00697   return anchor->last;
00698 }
00699 #endif
00700 
00701 static LINK_ELEMENT *
00702 POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
00703 {
00704     LINK_ELEMENT *elem = anchor->last;
00705     anchor->last = anchor->last->prev;
00706     anchor->last->next = 0;
00707     verify_list("pop", anchor);
00708     return elem;
00709 }
00710 #if CPDEBUG < 0
00711 #define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
00712 #endif
00713 
00714 #if 0 /* unused */
00715 static LINK_ELEMENT *
00716 SHIFT_ELEMENT(LINK_ANCHOR *anchor)
00717 {
00718     LINK_ELEMENT *elem = anchor->anchor.next;
00719     if (elem) {
00720         anchor->anchor.next = elem->next;
00721     }
00722     return elem;
00723 }
00724 #endif
00725 
00726 #if 0 /* unused */
00727 static int
00728 LIST_SIZE(LINK_ANCHOR *anchor)
00729 {
00730     LINK_ELEMENT *elem = anchor->anchor.next;
00731     int size = 0;
00732     while (elem) {
00733         size += 1;
00734         elem = elem->next;
00735     }
00736     return size;
00737 }
00738 #endif
00739 
00740 static int
00741 LIST_SIZE_ZERO(LINK_ANCHOR *anchor)
00742 {
00743     if (anchor->anchor.next == 0) {
00744         return 1;
00745     }
00746     else {
00747         return 0;
00748     }
00749 }
00750 
00751 /*
00752  * anc1: e1, e2, e3
00753  * anc2: e4, e5
00754  *#=>
00755  * anc1: e1, e2, e3, e4, e5
00756  * anc2: e4, e5 (broken)
00757  */
00758 static void
00759 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
00760 {
00761     if (anc2->anchor.next) {
00762         anc1->last->next = anc2->anchor.next;
00763         anc2->anchor.next->prev = anc1->last;
00764         anc1->last = anc2->last;
00765     }
00766     verify_list("append", anc1);
00767 }
00768 #if CPDEBUG < 0
00769 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
00770 #endif
00771 
00772 /*
00773  * anc1: e1, e2, e3
00774  * anc2: e4, e5
00775  *#=>
00776  * anc1: e4, e5, e1, e2, e3
00777  * anc2: e4, e5 (broken)
00778  */
00779 static void
00780 INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
00781 {
00782     if (anc2->anchor.next) {
00783         LINK_ELEMENT *first = anc1->anchor.next;
00784         anc1->anchor.next = anc2->anchor.next;
00785         anc1->anchor.next->prev = &anc1->anchor;
00786         anc2->last->next = first;
00787         if (first) {
00788             first->prev = anc2->last;
00789         }
00790         else {
00791             anc1->last = anc2->last;
00792         }
00793     }
00794 
00795     verify_list("append", anc1);
00796 }
00797 #if CPDEBUG < 0
00798 #define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, (anc1), (anc2))
00799 #endif
00800 
00801 #if 0 /* unused */
00802 /*
00803  * anc1: e1, e2, e3
00804  * anc2: e4, e5
00805  *#=>
00806  * anc1: e4, e5
00807  * anc2: e1, e2, e3
00808  */
00809 static void
00810 SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
00811 {
00812     LINK_ANCHOR tmp = *anc2;
00813 
00814     /* it has bug */
00815     *anc2 = *anc1;
00816     *anc1 = tmp;
00817 
00818     verify_list("swap1", anc1);
00819     verify_list("swap2", anc2);
00820 }
00821 #if CPDEBUG < 0
00822 #define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, (anc1), (anc2))
00823 #endif
00824 
00825 static LINK_ANCHOR *
00826 REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc)
00827 {
00828     LINK_ELEMENT *first, *last, *elem, *e;
00829     first = &anc->anchor;
00830     elem = first->next;
00831     last = anc->last;
00832 
00833     if (elem != 0) {
00834         anc->anchor.next = last;
00835         anc->last = elem;
00836     }
00837     else {
00838         /* null list */
00839         return anc;
00840     }
00841     while (elem) {
00842         e = elem->next;
00843         elem->next = elem->prev;
00844         elem->prev = e;
00845         elem = e;
00846     }
00847 
00848     first->next = last;
00849     last->prev = first;
00850     anc->last->next = 0;
00851 
00852     verify_list("reverse", anc);
00853     return anc;
00854 }
00855 #if CPDEBUG < 0
00856 #define REVERSE_LIST(anc) REVERSE_LIST(iseq, (anc))
00857 #endif
00858 #endif
00859 
00860 #if CPDEBUG && 0
00861 static void
00862 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
00863 {
00864     LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
00865     printf("----\n");
00866     printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
00867            anchor->anchor.next, anchor->last);
00868     while (list) {
00869         printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
00870                list->prev, FIX2INT(list->type));
00871         list = list->next;
00872     }
00873     printf("----\n");
00874 
00875     dump_disasm_list(anchor->anchor.next);
00876     verify_list("debug list", anchor);
00877 }
00878 #if CPDEBUG < 0
00879 #define debug_list(anc) debug_list(iseq, (anc))
00880 #endif
00881 #endif
00882 
00883 static LABEL *
00884 new_label_body(rb_iseq_t *iseq, long line)
00885 {
00886     LABEL *labelobj = compile_data_alloc_label(iseq);
00887 
00888     labelobj->link.type = ISEQ_ELEMENT_LABEL;
00889     labelobj->link.next = 0;
00890 
00891     labelobj->label_no = iseq->compile_data->label_no++;
00892     labelobj->sc_state = 0;
00893     labelobj->sp = -1;
00894     return labelobj;
00895 }
00896 
00897 static ADJUST *
00898 new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
00899 {
00900     ADJUST *adjust = compile_data_alloc_adjust(iseq);
00901     adjust->link.type = ISEQ_ELEMENT_ADJUST;
00902     adjust->link.next = 0;
00903     adjust->label = label;
00904     adjust->line_no = line;
00905     return adjust;
00906 }
00907 
00908 static INSN *
00909 new_insn_core(rb_iseq_t *iseq, int line_no,
00910               int insn_id, int argc, VALUE *argv)
00911 {
00912     INSN *iobj = compile_data_alloc_insn(iseq);
00913     /* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
00914 
00915     iobj->link.type = ISEQ_ELEMENT_INSN;
00916     iobj->link.next = 0;
00917     iobj->insn_id = insn_id;
00918     iobj->line_no = line_no;
00919     iobj->operands = argv;
00920     iobj->operand_size = argc;
00921     iobj->sc_state = 0;
00922     return iobj;
00923 }
00924 
00925 static INSN *
00926 new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...)
00927 {
00928     VALUE *operands = 0;
00929     va_list argv;
00930     if (argc > 0) {
00931         int i;
00932         va_init_list(argv, argc);
00933         operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
00934         for (i = 0; i < argc; i++) {
00935             VALUE v = va_arg(argv, VALUE);
00936             operands[i] = v;
00937         }
00938         va_end(argv);
00939     }
00940     return new_insn_core(iseq, line_no, insn_id, argc, operands);
00941 }
00942 
00943 static rb_call_info_t *
00944 new_callinfo(rb_iseq_t *iseq, ID mid, int argc, VALUE block, unsigned long flag)
00945 {
00946     rb_call_info_t *ci = (rb_call_info_t *)compile_data_alloc(iseq, sizeof(rb_call_info_t));
00947     ci->mid = mid;
00948     ci->flag = flag;
00949     ci->orig_argc = argc;
00950     ci->argc = argc;
00951 
00952     if (block) {
00953         GetISeqPtr(block, ci->blockiseq);
00954     }
00955     else {
00956         ci->blockiseq = 0;
00957         if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG))) {
00958             ci->flag |= VM_CALL_ARGS_SKIP_SETUP;
00959         }
00960     }
00961     ci->vmstat = 0;
00962     ci->blockptr = 0;
00963     ci->recv = Qundef;
00964     ci->call = 0; /* TODO: should set default function? */
00965 
00966     ci->aux.index = iseq->callinfo_size++;
00967 
00968     return ci;
00969 }
00970 
00971 static INSN *
00972 new_insn_send(rb_iseq_t *iseq, int line_no, VALUE id, VALUE argc, VALUE block, VALUE flag)
00973 {
00974     VALUE *operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 1);
00975     operands[0] = (VALUE)new_callinfo(iseq, SYM2ID(id), FIX2INT(argc), block, FIX2INT(flag));
00976     return new_insn_core(iseq, line_no, BIN(send), 1, operands);
00977 }
00978 
00979 static VALUE
00980 new_child_iseq(rb_iseq_t *iseq, NODE *node,
00981                VALUE name, VALUE parent, enum iseq_type type, int line_no)
00982 {
00983     VALUE ret;
00984 
00985     debugs("[new_child_iseq]> ---------------------------------------\n");
00986     ret = rb_iseq_new_with_opt(node, name,
00987                                iseq_path(iseq->self), iseq_absolute_path(iseq->self),
00988                                INT2FIX(line_no), parent, type, iseq->compile_data->option);
00989     debugs("[new_child_iseq]< ---------------------------------------\n");
00990     iseq_add_mark_object(iseq, ret);
00991     return ret;
00992 }
00993 
00994 static int
00995 iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
00996 {
00997     /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
00998 
00999     if (compile_debug > 5)
01000         dump_disasm_list(FIRST_ELEMENT(anchor));
01001 
01002     debugs("[compile step 3.1 (iseq_optimize)]\n");
01003     iseq_optimize(iseq, anchor);
01004 
01005     if (compile_debug > 5)
01006         dump_disasm_list(FIRST_ELEMENT(anchor));
01007 
01008     if (iseq->compile_data->option->instructions_unification) {
01009         debugs("[compile step 3.2 (iseq_insns_unification)]\n");
01010         iseq_insns_unification(iseq, anchor);
01011         if (compile_debug > 5)
01012             dump_disasm_list(FIRST_ELEMENT(anchor));
01013     }
01014 
01015     if (iseq->compile_data->option->stack_caching) {
01016         debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
01017         iseq_set_sequence_stackcaching(iseq, anchor);
01018         if (compile_debug > 5)
01019             dump_disasm_list(FIRST_ELEMENT(anchor));
01020     }
01021 
01022     debugs("[compile step 4.1 (iseq_set_sequence)]\n");
01023     iseq_set_sequence(iseq, anchor);
01024     if (compile_debug > 5)
01025         dump_disasm_list(FIRST_ELEMENT(anchor));
01026 
01027     debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
01028     iseq_set_exception_table(iseq);
01029 
01030     debugs("[compile step 4.3 (set_optargs_table)] \n");
01031     iseq_set_optargs_table(iseq);
01032 
01033     debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
01034     rb_iseq_translate_threaded_code(iseq);
01035 
01036     if (compile_debug > 1) {
01037         VALUE str = rb_iseq_disasm(iseq->self);
01038         printf("%s\n", StringValueCStr(str));
01039         fflush(stdout);
01040     }
01041     debugs("[compile step: finish]\n");
01042 
01043     return 0;
01044 }
01045 
01046 static int
01047 iseq_set_exception_local_table(rb_iseq_t *iseq)
01048 {
01049     ID id_dollar_bang;
01050 
01051     CONST_ID(id_dollar_bang, "#$!");
01052     iseq->local_table = (ID *)ALLOC_N(ID, 1);
01053     iseq->local_table_size = 1;
01054     iseq->local_size = iseq->local_table_size + 1;
01055     iseq->local_table[0] = id_dollar_bang;
01056     return COMPILE_OK;
01057 }
01058 
01059 static int
01060 get_lvar_level(rb_iseq_t *iseq)
01061 {
01062     int lev = 0;
01063     while (iseq != iseq->local_iseq) {
01064         lev++;
01065         iseq = iseq->parent_iseq;
01066     }
01067     return lev;
01068 }
01069 
01070 static int
01071 get_dyna_var_idx_at_raw(rb_iseq_t *iseq, ID id)
01072 {
01073     int i;
01074 
01075     for (i = 0; i < iseq->local_table_size; i++) {
01076         if (iseq->local_table[i] == id) {
01077             return i;
01078         }
01079     }
01080     return -1;
01081 }
01082 
01083 static int
01084 get_local_var_idx(rb_iseq_t *iseq, ID id)
01085 {
01086     int idx = get_dyna_var_idx_at_raw(iseq->local_iseq, id);
01087 
01088     if (idx < 0) {
01089         rb_bug("get_local_var_idx: %d", idx);
01090     }
01091 
01092     return idx;
01093 }
01094 
01095 static int
01096 get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls)
01097 {
01098     int lv = 0, idx = -1;
01099 
01100     while (iseq) {
01101         idx = get_dyna_var_idx_at_raw(iseq, id);
01102         if (idx >= 0) {
01103             break;
01104         }
01105         iseq = iseq->parent_iseq;
01106         lv++;
01107     }
01108 
01109     if (idx < 0) {
01110         rb_bug("get_dyna_var_idx: -1");
01111     }
01112 
01113     *level = lv;
01114     *ls = iseq->local_size;
01115     return idx;
01116 }
01117 
01118 static int
01119 iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
01120 {
01121     debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
01122 
01123     if (node_args) {
01124         struct rb_args_info *args = node_args->nd_ainfo;
01125         ID rest_id = 0;
01126         int last_comma = 0;
01127         ID block_id = 0;
01128 
01129         if (nd_type(node_args) != NODE_ARGS) {
01130             rb_bug("iseq_set_arguments: NODE_ARGS is expected, but %s",
01131                    ruby_node_name(nd_type(node_args)));
01132         }
01133 
01134 
01135         iseq->argc = (int)args->pre_args_num;
01136         debugs("  - argc: %d\n", iseq->argc);
01137 
01138         rest_id = args->rest_arg;
01139         if (rest_id == 1) {
01140             last_comma = 1;
01141             rest_id = 0;
01142         }
01143         block_id = args->block_arg;
01144 
01145         if (args->first_post_arg) {
01146             iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg);
01147             iseq->arg_post_len = args->post_args_num;
01148         }
01149 
01150         if (args->opt_args) {
01151             NODE *node = args->opt_args;
01152             LABEL *label;
01153             VALUE labels = rb_ary_tmp_new(1);
01154             int i = 0, j;
01155 
01156             while (node) {
01157                 label = NEW_LABEL(nd_line(node));
01158                 rb_ary_push(labels, (VALUE)label | 1);
01159                 ADD_LABEL(optargs, label);
01160                 COMPILE_POPED(optargs, "optarg", node->nd_body);
01161                 node = node->nd_next;
01162                 i += 1;
01163             }
01164 
01165             /* last label */
01166             label = NEW_LABEL(nd_line(node_args));
01167             rb_ary_push(labels, (VALUE)label | 1);
01168             ADD_LABEL(optargs, label);
01169             i += 1;
01170 
01171             iseq->arg_opts = i;
01172             iseq->arg_opt_table = ALLOC_N(VALUE, i);
01173             MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i);
01174             for (j = 0; j < i; j++) {
01175                 iseq->arg_opt_table[j] &= ~1;
01176             }
01177             rb_ary_clear(labels);
01178         }
01179         else {
01180             iseq->arg_opts = 0;
01181         }
01182 
01183         if (args->kw_args) {
01184             NODE *node = args->kw_args;
01185             VALUE keywords = rb_ary_tmp_new(1);
01186             int i = 0, j;
01187 
01188             iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
01189             COMPILE(optargs, "kwarg", args->kw_rest_arg);
01190             while (node) {
01191                 rb_ary_push(keywords, INT2FIX(node->nd_body->nd_vid));
01192                 COMPILE_POPED(optargs, "kwarg", node); /* nd_type(node) == NODE_KW_ARG */
01193                 node = node->nd_next;
01194                 i += 1;
01195             }
01196             iseq->arg_keyword_check = (args->kw_rest_arg->nd_vid & ID_SCOPE_MASK) == ID_JUNK;
01197             iseq->arg_keywords = i;
01198             iseq->arg_keyword_table = ALLOC_N(ID, i);
01199             for (j = 0; j < i; j++) {
01200                 iseq->arg_keyword_table[j] = FIX2INT(RARRAY_PTR(keywords)[j]);
01201             }
01202             ADD_INSN(optargs, nd_line(args->kw_args), pop);
01203         }
01204         else if (args->kw_rest_arg) {
01205             iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
01206             COMPILE(optargs, "kwarg", args->kw_rest_arg);
01207             ADD_INSN(optargs, nd_line(args->kw_rest_arg), pop);
01208         }
01209         else {
01210             iseq->arg_keyword = -1;
01211         }
01212 
01213         if (args->pre_init) { /* m_init */
01214             COMPILE_POPED(optargs, "init arguments (m)", args->pre_init);
01215         }
01216         if (args->post_init) { /* p_init */
01217             COMPILE_POPED(optargs, "init arguments (p)", args->post_init);
01218         }
01219 
01220         if (rest_id) {
01221             iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id);
01222 
01223             if (iseq->arg_rest == -1) {
01224                 rb_bug("arg_rest: -1");
01225             }
01226 
01227             if (iseq->arg_post_start == 0) {
01228                 iseq->arg_post_start = iseq->arg_rest + 1;
01229             }
01230         }
01231 
01232         if (block_id) {
01233             iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id);
01234         }
01235 
01236         if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 ||
01237             iseq->arg_rest != -1 || iseq->arg_block != -1 ||
01238             iseq->arg_keyword != -1) {
01239             iseq->arg_simple = 0;
01240 
01241             /* set arg_size: size of arguments */
01242             if (iseq->arg_keyword != -1) {
01243                 iseq->arg_size = iseq->arg_keyword + 1;
01244             }
01245             else if (iseq->arg_block != -1) {
01246                 iseq->arg_size = iseq->arg_block + 1;
01247             }
01248             else if (iseq->arg_post_len) {
01249                 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
01250             }
01251             else if (iseq->arg_rest != -1) {
01252                 iseq->arg_size = iseq->arg_rest + 1;
01253             }
01254             else if (iseq->arg_opts) {
01255                 iseq->arg_size = iseq->argc + iseq->arg_opts - 1;
01256             }
01257             else {
01258                 iseq->arg_size = iseq->argc;
01259             }
01260         }
01261         else {
01262             iseq->arg_simple = 1;
01263             iseq->arg_size = iseq->argc;
01264         }
01265 
01266         if (iseq->type == ISEQ_TYPE_BLOCK) {
01267             if (iseq->arg_opts == 0 && iseq->arg_post_len == 0 &&
01268                 iseq->arg_rest == -1 && iseq->arg_keyword == -1) {
01269                 if (iseq->argc == 1 && last_comma == 0) {
01270                     /* {|a|} */
01271                     iseq->arg_simple |= 0x02;
01272                 }
01273             }
01274         }
01275     }
01276     else {
01277         iseq->arg_simple = 1;
01278     }
01279 
01280     return COMPILE_OK;
01281 }
01282 
01283 static int
01284 iseq_set_local_table(rb_iseq_t *iseq, ID *tbl)
01285 {
01286     int size;
01287 
01288     if (tbl) {
01289         size = (int)*tbl;
01290         tbl++;
01291     }
01292     else {
01293         size = 0;
01294     }
01295 
01296     if (size > 0) {
01297         iseq->local_table = (ID *)ALLOC_N(ID, size);
01298         MEMCPY(iseq->local_table, tbl, ID, size);
01299     }
01300 
01301     iseq->local_size = iseq->local_table_size = size;
01302     iseq->local_size += 1;
01303     /*
01304       if (lfp == dfp ) { // top, class, method
01305           dfp[-1]: svar
01306       else {             // block
01307           dfp[-1]: cref
01308       }
01309      */
01310 
01311     debugs("iseq_set_local_table: %d, %d\n", iseq->local_size, iseq->local_table_size);
01312     return COMPILE_OK;
01313 }
01314 
01315 static int
01316 cdhash_cmp(VALUE val, VALUE lit)
01317 {
01318     if (val == lit) return 0;
01319     if (SPECIAL_CONST_P(lit)) {
01320         return val != lit;
01321     }
01322     if (SPECIAL_CONST_P(val) || BUILTIN_TYPE(val) != BUILTIN_TYPE(lit)) {
01323         return -1;
01324     }
01325     if (BUILTIN_TYPE(lit) == T_STRING) {
01326         return rb_str_hash_cmp(lit, val);
01327     }
01328     return !rb_eql(lit, val);
01329 }
01330 
01331 static st_index_t
01332 cdhash_hash(VALUE a)
01333 {
01334     if (SPECIAL_CONST_P(a)) return (st_index_t)a;
01335     if (RB_TYPE_P(a, T_STRING)) return rb_str_hash(a);
01336     {
01337         VALUE hval = rb_hash(a);
01338         return (st_index_t)FIX2LONG(hval);
01339     }
01340 }
01341 
01342 static const struct st_hash_type cdhash_type = {
01343     cdhash_cmp,
01344     cdhash_hash,
01345 };
01346 
01347 struct cdhash_set_label_struct {
01348     VALUE hash;
01349     int pos;
01350     int len;
01351 };
01352 
01353 static int
01354 cdhash_set_label_i(VALUE key, VALUE val, void *ptr)
01355 {
01356     struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
01357     LABEL *lobj = (LABEL *)(val & ~1);
01358     rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
01359     return ST_CONTINUE;
01360 }
01361 
01365 static int
01366 iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
01367 {
01368     LABEL *lobj;
01369     INSN *iobj;
01370     struct iseq_line_info_entry *line_info_table;
01371     unsigned int last_line = 0;
01372     LINK_ELEMENT *list;
01373     VALUE *generated_iseq;
01374 
01375     int k, pos, sp, stack_max = 0, line = 0;
01376 
01377     /* set label position */
01378     list = FIRST_ELEMENT(anchor);
01379     k = pos = 0;
01380     while (list) {
01381         switch (list->type) {
01382           case ISEQ_ELEMENT_INSN:
01383             {
01384                 iobj = (INSN *)list;
01385                 line = iobj->line_no;
01386                 pos += insn_data_length(iobj);
01387                 k++;
01388                 break;
01389             }
01390           case ISEQ_ELEMENT_LABEL:
01391             {
01392                 lobj = (LABEL *)list;
01393                 lobj->position = pos;
01394                 lobj->set = TRUE;
01395                 break;
01396             }
01397           case ISEQ_ELEMENT_NONE:
01398             {
01399                 /* ignore */
01400                 break;
01401             }
01402           case ISEQ_ELEMENT_ADJUST:
01403             {
01404                 ADJUST *adjust = (ADJUST *)list;
01405                 if (adjust->line_no != -1) {
01406                     pos += 2 /* insn + 1 operand */;
01407                     k++;
01408                 }
01409                 break;
01410             }
01411           default:
01412             dump_disasm_list(FIRST_ELEMENT(anchor));
01413             dump_disasm_list(list);
01414             rb_compile_error(RSTRING_PTR(iseq->location.path), line,
01415                              "error: set_sequence");
01416             break;
01417         }
01418         list = list->next;
01419     }
01420 
01421     /* make instruction sequence */
01422     generated_iseq = ALLOC_N(VALUE, pos);
01423     line_info_table = ALLOC_N(struct iseq_line_info_entry, k);
01424     iseq->ic_entries = ALLOC_N(struct iseq_inline_cache_entry, iseq->ic_size);
01425     MEMZERO(iseq->ic_entries, struct iseq_inline_cache_entry, iseq->ic_size);
01426     iseq->callinfo_entries = ALLOC_N(rb_call_info_t, iseq->callinfo_size);
01427     /* MEMZERO(iseq->callinfo_entries, rb_call_info_t, iseq->callinfo_size); */
01428 
01429     list = FIRST_ELEMENT(anchor);
01430     k = pos = sp = 0;
01431 
01432     while (list) {
01433         switch (list->type) {
01434           case ISEQ_ELEMENT_INSN:
01435             {
01436                 int j, len, insn;
01437                 const char *types;
01438                 VALUE *operands;
01439 
01440                 iobj = (INSN *)list;
01441 
01442                 /* update sp */
01443                 sp = calc_sp_depth(sp, iobj);
01444                 if (sp > stack_max) {
01445                     stack_max = sp;
01446                 }
01447 
01448                 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
01449                 operands = iobj->operands;
01450                 insn = iobj->insn_id;
01451                 generated_iseq[pos] = insn;
01452                 types = insn_op_types(insn);
01453                 len = insn_len(insn);
01454 
01455                 /* operand check */
01456                 if (iobj->operand_size != len - 1) {
01457                     /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
01458                     dump_disasm_list(list);
01459                     rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
01460                                      "operand size miss! (%d for %d)",
01461                                      iobj->operand_size, len - 1);
01462                     xfree(generated_iseq);
01463                     xfree(line_info_table);
01464                     return 0;
01465                 }
01466 
01467                 for (j = 0; types[j]; j++) {
01468                     char type = types[j];
01469                     /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
01470                     switch (type) {
01471                       case TS_OFFSET:
01472                         {
01473                             /* label(destination position) */
01474                             lobj = (LABEL *)operands[j];
01475                             if (!lobj->set) {
01476                                 rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
01477                                                  "unknown label");
01478                             }
01479                             if (lobj->sp == -1) {
01480                                 lobj->sp = sp;
01481                             }
01482                             generated_iseq[pos + 1 + j] = lobj->position - (pos + len);
01483                             break;
01484                         }
01485                       case TS_CDHASH:
01486                         {
01487                             VALUE map = operands[j];
01488                             struct cdhash_set_label_struct data;
01489                             data.hash = map;
01490                             data.pos = pos;
01491                             data.len = len;
01492                             rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
01493 
01494                             hide_obj(map);
01495                             generated_iseq[pos + 1 + j] = map;
01496                             break;
01497                         }
01498                       case TS_LINDEX:
01499                       case TS_NUM:      /* ulong */
01500                         generated_iseq[pos + 1 + j] = FIX2INT(operands[j]);
01501                         break;
01502                       case TS_ISEQ:     /* iseq */
01503                         {
01504                             VALUE v = operands[j];
01505                             rb_iseq_t *block = 0;
01506                             if (v) {
01507                                 GetISeqPtr(v, block);
01508                             }
01509                             generated_iseq[pos + 1 + j] = (VALUE)block;
01510                             break;
01511                         }
01512                       case TS_VALUE:    /* VALUE */
01513                         {
01514                             VALUE v = operands[j];
01515                             generated_iseq[pos + 1 + j] = v;
01516                             /* to mark ruby object */
01517                             iseq_add_mark_object(iseq, v);
01518                             break;
01519                         }
01520                       case TS_IC: /* inline cache */
01521                         {
01522                             int ic_index = FIX2INT(operands[j]);
01523                             IC ic = &iseq->ic_entries[ic_index];
01524                             if (UNLIKELY(ic_index >= iseq->ic_size)) {
01525                                 rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->ic_size);
01526                             }
01527                             generated_iseq[pos + 1 + j] = (VALUE)ic;
01528                             break;
01529                         }
01530                       case TS_CALLINFO: /* call info */
01531                         {
01532                             rb_call_info_t *base_ci = (rb_call_info_t *)operands[j];
01533                             rb_call_info_t *ci = &iseq->callinfo_entries[base_ci->aux.index];
01534                             *ci = *base_ci;
01535 
01536                             if (UNLIKELY(base_ci->aux.index >= iseq->callinfo_size)) {
01537                                 rb_bug("iseq_set_sequence: ci_index overflow: index: %d, size: %d", base_ci->argc, iseq->callinfo_size);
01538                             }
01539                             generated_iseq[pos + 1 + j] = (VALUE)ci;
01540                             break;
01541                         }
01542                       case TS_ID: /* ID */
01543                         generated_iseq[pos + 1 + j] = SYM2ID(operands[j]);
01544                         break;
01545                       case TS_GENTRY:
01546                         {
01547                             struct rb_global_entry *entry =
01548                                 (struct rb_global_entry *)(operands[j] & (~1));
01549                             generated_iseq[pos + 1 + j] = (VALUE)entry;
01550                         }
01551                         break;
01552                       default:
01553                         rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
01554                                          "unknown operand type: %c", type);
01555                         xfree(generated_iseq);
01556                         xfree(line_info_table);
01557                         return 0;
01558                     }
01559                 }
01560                 if (last_line != iobj->line_no) {
01561                     line_info_table[k].line_no = last_line = iobj->line_no;
01562                     line_info_table[k].position = pos;
01563                     k++;
01564                 }
01565                 pos += len;
01566                 break;
01567             }
01568           case ISEQ_ELEMENT_LABEL:
01569             {
01570                 lobj = (LABEL *)list;
01571                 if (lobj->sp == -1) {
01572                     lobj->sp = sp;
01573                 }
01574                 else {
01575                     sp = lobj->sp;
01576                 }
01577                 break;
01578             }
01579           case ISEQ_ELEMENT_ADJUST:
01580             {
01581                 ADJUST *adjust = (ADJUST *)list;
01582                 int orig_sp = sp;
01583 
01584                 if (adjust->label) {
01585                     sp = adjust->label->sp;
01586                 }
01587                 else {
01588                     sp = 0;
01589                 }
01590 
01591                 if (adjust->line_no != -1) {
01592                     if (orig_sp - sp > 0) {
01593                         if (last_line != (unsigned int)adjust->line_no) {
01594                             line_info_table[k].line_no = last_line = adjust->line_no;
01595                             line_info_table[k].position = pos;
01596                             k++;
01597                         }
01598                         generated_iseq[pos++] = BIN(adjuststack);
01599                         generated_iseq[pos++] = orig_sp - sp;
01600                     }
01601                     else if (orig_sp - sp == 0) {
01602                         /* jump to next insn */
01603                         if (last_line != (unsigned int)adjust->line_no) {
01604                             line_info_table[k].line_no = last_line = adjust->line_no;
01605                             line_info_table[k].position = pos;
01606                             k++;
01607                         }
01608                         generated_iseq[pos++] = BIN(jump);
01609                         generated_iseq[pos++] = 0;
01610                     }
01611                     else {
01612                         rb_bug("iseq_set_sequence: adjust bug");
01613                     }
01614                 }
01615                 break;
01616             }
01617           default:
01618             /* ignore */
01619             break;
01620         }
01621         list = list->next;
01622     }
01623 
01624 #if 0 /* XXX */
01625     /* this check need dead code elimination */
01626     if (sp != 1) {
01627         rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
01628     }
01629 #endif
01630 
01631     iseq->iseq = (void *)generated_iseq;
01632     iseq->iseq_size = pos;
01633     iseq->stack_max = stack_max;
01634 
01635     line_info_table = ruby_xrealloc(line_info_table, k * sizeof(struct iseq_line_info_entry));
01636     iseq->line_info_table = line_info_table;
01637     iseq->line_info_size = k;
01638 
01639     return COMPILE_OK;
01640 }
01641 
01642 static int
01643 label_get_position(LABEL *lobj)
01644 {
01645     return lobj->position;
01646 }
01647 
01648 static int
01649 label_get_sp(LABEL *lobj)
01650 {
01651     return lobj->sp;
01652 }
01653 
01654 static int
01655 iseq_set_exception_table(rb_iseq_t *iseq)
01656 {
01657     VALUE *tptr, *ptr;
01658     int tlen, i;
01659     struct iseq_catch_table_entry *entry;
01660 
01661     tlen = (int)RARRAY_LEN(iseq->compile_data->catch_table_ary);
01662     tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary);
01663 
01664     iseq->catch_table = tlen ? ALLOC_N(struct iseq_catch_table_entry, tlen) : 0;
01665     iseq->catch_table_size = tlen;
01666 
01667     for (i = 0; i < tlen; i++) {
01668         ptr = RARRAY_PTR(tptr[i]);
01669         entry = &iseq->catch_table[i];
01670         entry->type = (enum catch_type)(ptr[0] & 0xffff);
01671         entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
01672         entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
01673         entry->iseq = ptr[3];
01674 
01675         /* register iseq as mark object */
01676         if (entry->iseq != 0) {
01677             iseq_add_mark_object(iseq, entry->iseq);
01678         }
01679 
01680         /* stack depth */
01681         if (ptr[4]) {
01682             LABEL *lobj = (LABEL *)(ptr[4] & ~1);
01683             entry->cont = label_get_position(lobj);
01684             entry->sp = label_get_sp(lobj);
01685 
01686             /* TODO: Dirty Hack!  Fix me */
01687             if (entry->type == CATCH_TYPE_RESCUE ||
01688                 entry->type == CATCH_TYPE_BREAK ||
01689                 entry->type == CATCH_TYPE_NEXT) {
01690                 entry->sp--;
01691             }
01692         }
01693         else {
01694             entry->cont = 0;
01695         }
01696     }
01697 
01698     iseq->compile_data->catch_table_ary = 0;    /* free */
01699     return COMPILE_OK;
01700 }
01701 
01702 /*
01703  * set optional argument table
01704  *   def foo(a, b=expr1, c=expr2)
01705  *   =>
01706  *    b:
01707  *      expr1
01708  *    c:
01709  *      expr2
01710  */
01711 static int
01712 iseq_set_optargs_table(rb_iseq_t *iseq)
01713 {
01714     int i;
01715 
01716     if (iseq->arg_opts != 0) {
01717         for (i = 0; i < iseq->arg_opts; i++) {
01718             iseq->arg_opt_table[i] =
01719                 label_get_position((LABEL *)iseq->arg_opt_table[i]);
01720         }
01721     }
01722     return COMPILE_OK;
01723 }
01724 
01725 static LINK_ELEMENT *
01726 get_destination_insn(INSN *iobj)
01727 {
01728     LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
01729     LINK_ELEMENT *list;
01730 
01731     list = lobj->link.next;
01732     while (list) {
01733         if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
01734             break;
01735         }
01736         list = list->next;
01737     }
01738     return list;
01739 }
01740 
01741 static LINK_ELEMENT *
01742 get_next_insn(INSN *iobj)
01743 {
01744     LINK_ELEMENT *list = iobj->link.next;
01745 
01746     while (list) {
01747         if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
01748             return list;
01749         }
01750         list = list->next;
01751     }
01752     return 0;
01753 }
01754 
01755 static LINK_ELEMENT *
01756 get_prev_insn(INSN *iobj)
01757 {
01758     LINK_ELEMENT *list = iobj->link.prev;
01759 
01760     while (list) {
01761         if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
01762             return list;
01763         }
01764         list = list->prev;
01765     }
01766     return 0;
01767 }
01768 
01769 static int
01770 iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
01771 {
01772     INSN *iobj = (INSN *)list;
01773   again:
01774     if (iobj->insn_id == BIN(jump)) {
01775         INSN *niobj, *diobj, *piobj;
01776         /*
01777          *  useless jump elimination:
01778          *     jump LABEL1
01779          *     ...
01780          *   LABEL1:
01781          *     jump LABEL2
01782          *
01783          *   => in this case, first jump instruction should jump to
01784          *      LABEL2 directly
01785          */
01786         diobj = (INSN *)get_destination_insn(iobj);
01787         niobj = (INSN *)get_next_insn(iobj);
01788 
01789         if (diobj == niobj) {
01790             /*
01791              *   jump LABEL
01792              *  LABEL:
01793              * =>
01794              *   LABEL:
01795              */
01796             REMOVE_ELEM(&iobj->link);
01797         }
01798         else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
01799             if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
01800                 OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0);
01801                 goto again;
01802             }
01803         }
01804         else if (diobj->insn_id == BIN(leave)) {
01805             /*
01806              *  jump LABEL
01807              *  ...
01808              * LABEL:
01809              *  leave
01810              * =>
01811              *  leave
01812              *  ...
01813              * LABEL:
01814              *  leave
01815              */
01816             INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave),
01817                                         diobj->operand_size, diobj->operands);
01818             INSN *popiobj = new_insn_core(iseq, iobj->line_no,
01819                                           BIN(pop), 0, 0);
01820             /* replace */
01821             REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj);
01822             INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj);
01823             iobj = popiobj;
01824         }
01825         /*
01826          * useless jump elimination (if/unless destination):
01827          *   if   L1
01828          *   jump L2
01829          * L1:
01830          *   ...
01831          * L2:
01832          *
01833          * ==>
01834          *   unless L2
01835          * L1:
01836          *   ...
01837          * L2:
01838          */
01839         else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 &&
01840                  (piobj->insn_id == BIN(branchif) ||
01841                   piobj->insn_id == BIN(branchunless))) {
01842             if (niobj == (INSN *)get_destination_insn(piobj)) {
01843                 piobj->insn_id = (piobj->insn_id == BIN(branchif))
01844                   ? BIN(branchunless) : BIN(branchif);
01845                 OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0);
01846                 REMOVE_ELEM(&iobj->link);
01847             }
01848         }
01849     }
01850 
01851     if (iobj->insn_id == BIN(branchif) ||
01852         iobj->insn_id == BIN(branchunless)) {
01853         /*
01854          *   if L1
01855          *   ...
01856          * L1:
01857          *   jump L2
01858          * =>
01859          *   if L2
01860          */
01861         INSN *nobj = (INSN *)get_destination_insn(iobj);
01862         if (nobj->insn_id == BIN(jump)) {
01863             OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
01864         }
01865     }
01866 
01867     if (do_tailcallopt && iobj->insn_id == BIN(leave)) {
01868         /*
01869          *  send ...
01870          *  leave
01871          * =>
01872          *  send ..., ... | VM_CALL_TAILCALL, ...
01873          *  leave # unreachable
01874          */
01875         INSN *piobj = (INSN *)get_prev_insn((INSN *)list);
01876 
01877         if (piobj->insn_id == BIN(send) || piobj->insn_id == BIN(opt_send_simple)) {
01878             rb_call_info_t *ci = (rb_call_info_t *)piobj->operands[0];
01879             if (ci->blockiseq == 0) {
01880                 ci->flag |= VM_CALL_TAILCALL;
01881             }
01882         }
01883     }
01884     return COMPILE_OK;
01885 }
01886 
01887 static int
01888 insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
01889 {
01890     int old_opsize = iobj->operand_size;
01891     iobj->insn_id = insn_id;
01892     iobj->operand_size = insn_len(insn_id) - 1;
01893 
01894     if (iobj->operand_size > old_opsize) {
01895         VALUE *old_operands = iobj->operands;
01896         if (insn_id != BIN(opt_neq)) {
01897             rb_bug("insn_set_specialized_instruction: unknown insn: %d", insn_id);
01898         }
01899         iobj->operands = (VALUE *)compile_data_alloc(iseq, iobj->operand_size * sizeof(VALUE));
01900         iobj->operands[0] = old_operands[0];
01901         iobj->operands[1] = (VALUE)new_callinfo(iseq, idEq, 1, 0, 0);
01902     }
01903 
01904     return COMPILE_OK;
01905 }
01906 
01907 static int
01908 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
01909 {
01910     if (iobj->insn_id == BIN(send)) {
01911         rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, 0);
01912 
01913 #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
01914         if (ci->blockiseq == 0 && (ci->flag & ~VM_CALL_ARGS_SKIP_SETUP) == 0) {
01915             switch (ci->orig_argc) {
01916               case 0:
01917                 switch (ci->mid) {
01918                   case idLength: SP_INSN(length); return COMPILE_OK;
01919                   case idSize:   SP_INSN(size);   return COMPILE_OK;
01920                   case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
01921                   case idSucc:   SP_INSN(succ);   return COMPILE_OK;
01922                   case idNot:    SP_INSN(not);    return COMPILE_OK;
01923                 }
01924                 break;
01925               case 1:
01926                 switch (ci->mid) {
01927                   case idPLUS:   SP_INSN(plus);   return COMPILE_OK;
01928                   case idMINUS:  SP_INSN(minus);  return COMPILE_OK;
01929                   case idMULT:   SP_INSN(mult);   return COMPILE_OK;
01930                   case idDIV:    SP_INSN(div);    return COMPILE_OK;
01931                   case idMOD:    SP_INSN(mod);    return COMPILE_OK;
01932                   case idEq:     SP_INSN(eq);     return COMPILE_OK;
01933                   case idNeq:    SP_INSN(neq);    return COMPILE_OK;
01934                   case idLT:     SP_INSN(lt);     return COMPILE_OK;
01935                   case idLE:     SP_INSN(le);     return COMPILE_OK;
01936                   case idGT:     SP_INSN(gt);     return COMPILE_OK;
01937                   case idGE:     SP_INSN(ge);     return COMPILE_OK;
01938                   case idLTLT:   SP_INSN(ltlt);   return COMPILE_OK;
01939                   case idAREF:   SP_INSN(aref);   return COMPILE_OK;
01940                 }
01941                 break;
01942             }
01943         }
01944         if (ci->flag & VM_CALL_ARGS_SKIP_SETUP) {
01945             iobj->insn_id = BIN(opt_send_simple);
01946         }
01947     }
01948 #undef SP_INSN
01949 
01950     return COMPILE_OK;
01951 }
01952 
01953 static int
01954 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
01955 {
01956     LINK_ELEMENT *list;
01957     const int do_peepholeopt = iseq->compile_data->option->peephole_optimization;
01958     const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization;
01959     const int do_si = iseq->compile_data->option->specialized_instruction;
01960     const int do_ou = iseq->compile_data->option->operands_unification;
01961     list = FIRST_ELEMENT(anchor);
01962 
01963     while (list) {
01964         if (list->type == ISEQ_ELEMENT_INSN) {
01965             if (do_peepholeopt) {
01966                 iseq_peephole_optimize(iseq, list, do_tailcallopt);
01967             }
01968             if (do_si) {
01969                 iseq_specialized_instruction(iseq, (INSN *)list);
01970             }
01971             if (do_ou) {
01972                 insn_operands_unification((INSN *)list);
01973             }
01974         }
01975         list = list->next;
01976     }
01977     return COMPILE_OK;
01978 }
01979 
01980 #if OPT_INSTRUCTIONS_UNIFICATION
01981 static INSN *
01982 new_unified_insn(rb_iseq_t *iseq,
01983                  int insn_id, int size, LINK_ELEMENT *seq_list)
01984 {
01985     INSN *iobj = 0;
01986     LINK_ELEMENT *list = seq_list;
01987     int i, argc = 0;
01988     VALUE *operands = 0, *ptr = 0;
01989 
01990 
01991     /* count argc */
01992     for (i = 0; i < size; i++) {
01993         iobj = (INSN *)list;
01994         argc += iobj->operand_size;
01995         list = list->next;
01996     }
01997 
01998     if (argc > 0) {
01999         ptr = operands =
02000             (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc);
02001     }
02002 
02003     /* copy operands */
02004     list = seq_list;
02005     for (i = 0; i < size; i++) {
02006         iobj = (INSN *)list;
02007         MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
02008         ptr += iobj->operand_size;
02009         list = list->next;
02010     }
02011 
02012     return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands);
02013 }
02014 #endif
02015 
02016 /*
02017  * This scheme can get more performance if do this optimize with
02018  * label address resolving.
02019  * It's future work (if compile time was bottle neck).
02020  */
02021 static int
02022 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
02023 {
02024 #if OPT_INSTRUCTIONS_UNIFICATION
02025     LINK_ELEMENT *list;
02026     INSN *iobj, *niobj;
02027     int id, k;
02028     intptr_t j;
02029 
02030     list = FIRST_ELEMENT(anchor);
02031     while (list) {
02032         if (list->type == ISEQ_ELEMENT_INSN) {
02033             iobj = (INSN *)list;
02034             id = iobj->insn_id;
02035             if (unified_insns_data[id] != 0) {
02036                 const int *const *entry = unified_insns_data[id];
02037                 for (j = 1; j < (intptr_t)entry[0]; j++) {
02038                     const int *unified = entry[j];
02039                     LINK_ELEMENT *li = list->next;
02040                     for (k = 2; k < unified[1]; k++) {
02041                         if (li->type != ISEQ_ELEMENT_INSN ||
02042                             ((INSN *)li)->insn_id != unified[k]) {
02043                             goto miss;
02044                         }
02045                         li = li->next;
02046                     }
02047                     /* matched */
02048                     niobj =
02049                         new_unified_insn(iseq, unified[0], unified[1] - 1,
02050                                          list);
02051 
02052                     /* insert to list */
02053                     niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
02054                     niobj->link.next = li;
02055                     if (li) {
02056                         li->prev = (LINK_ELEMENT *)niobj;
02057                     }
02058 
02059                     list->prev->next = (LINK_ELEMENT *)niobj;
02060                     list = (LINK_ELEMENT *)niobj;
02061                     break;
02062                   miss:;
02063                 }
02064             }
02065         }
02066         list = list->next;
02067     }
02068 #endif
02069     return COMPILE_OK;
02070 }
02071 
02072 #if OPT_STACK_CACHING
02073 
02074 #define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
02075 #define SC_NEXT(insn)       sc_insn_next[(insn)]
02076 
02077 #include "opt_sc.inc"
02078 
02079 static int
02080 insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state)
02081 {
02082     int nstate;
02083     int insn_id;
02084 
02085     insn_id = iobj->insn_id;
02086     iobj->insn_id = SC_INSN(insn_id, state);
02087     nstate = SC_NEXT(iobj->insn_id);
02088 
02089     if (insn_id == BIN(jump) ||
02090         insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
02091         LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
02092 
02093         if (lobj->sc_state != 0) {
02094             if (lobj->sc_state != nstate) {
02095                 dump_disasm_list((LINK_ELEMENT *)iobj);
02096                 dump_disasm_list((LINK_ELEMENT *)lobj);
02097                 printf("\n-- %d, %d\n", lobj->sc_state, nstate);
02098                 rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
02099                                  "insn_set_sc_state error\n");
02100                 return 0;
02101             }
02102         }
02103         else {
02104             lobj->sc_state = nstate;
02105         }
02106         if (insn_id == BIN(jump)) {
02107             nstate = SCS_XX;
02108         }
02109     }
02110     else if (insn_id == BIN(leave)) {
02111         nstate = SCS_XX;
02112     }
02113 
02114     return nstate;
02115 }
02116 
02117 static int
02118 label_set_sc_state(LABEL *lobj, int state)
02119 {
02120     if (lobj->sc_state != 0) {
02121         if (lobj->sc_state != state) {
02122             state = lobj->sc_state;
02123         }
02124     }
02125     else {
02126         lobj->sc_state = state;
02127     }
02128 
02129     return state;
02130 }
02131 
02132 
02133 #endif
02134 
02135 static int
02136 iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
02137 {
02138 #if OPT_STACK_CACHING
02139     LINK_ELEMENT *list;
02140     int state, insn_id;
02141 
02142     /* initialize */
02143     state = SCS_XX;
02144     list = FIRST_ELEMENT(anchor);
02145     /* dump_disasm_list(list); */
02146 
02147     /* for each list element */
02148     while (list) {
02149       redo_point:
02150         switch (list->type) {
02151           case ISEQ_ELEMENT_INSN:
02152             {
02153                 INSN *iobj = (INSN *)list;
02154                 insn_id = iobj->insn_id;
02155 
02156                 /* dump_disasm_list(list); */
02157 
02158                 switch (insn_id) {
02159                   case BIN(nop):
02160                     {
02161                         /* exception merge point */
02162                         if (state != SCS_AX) {
02163                             INSN *rpobj =
02164                                 new_insn_body(iseq, 0, BIN(reput), 0);
02165 
02166                             /* replace this insn */
02167                             REPLACE_ELEM(list, (LINK_ELEMENT *)rpobj);
02168                             list = (LINK_ELEMENT *)rpobj;
02169                             goto redo_point;
02170                         }
02171                         break;
02172                     }
02173                   case BIN(swap):
02174                     {
02175                         if (state == SCS_AB || state == SCS_BA) {
02176                             state = (state == SCS_AB ? SCS_BA : SCS_AB);
02177 
02178                             REMOVE_ELEM(list);
02179                             list = list->next;
02180                             goto redo_point;
02181                         }
02182                         break;
02183                     }
02184                   case BIN(pop):
02185                     {
02186                         switch (state) {
02187                           case SCS_AX:
02188                           case SCS_BX:
02189                             state = SCS_XX;
02190                             break;
02191                           case SCS_AB:
02192                             state = SCS_AX;
02193                             break;
02194                           case SCS_BA:
02195                             state = SCS_BX;
02196                             break;
02197                           case SCS_XX:
02198                             goto normal_insn;
02199                           default:
02200                             rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
02201                                              "unreachable");
02202                         }
02203                         /* remove useless pop */
02204                         REMOVE_ELEM(list);
02205                         list = list->next;
02206                         goto redo_point;
02207                     }
02208                   default:;
02209                     /* none */
02210                 }               /* end of switch */
02211               normal_insn:
02212                 state = insn_set_sc_state(iseq, iobj, state);
02213                 break;
02214             }
02215           case ISEQ_ELEMENT_LABEL:
02216             {
02217                 LABEL *lobj;
02218                 lobj = (LABEL *)list;
02219 
02220                 state = label_set_sc_state(lobj, state);
02221             }
02222           default:
02223             break;
02224         }
02225         list = list->next;
02226     }
02227 #endif
02228     return COMPILE_OK;
02229 }
02230 
02231 static int
02232 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int *cntp)
02233 {
02234     NODE *list = node->nd_next;
02235     VALUE lit = node->nd_lit;
02236     int cnt = 0;
02237 
02238     debugp_param("nd_lit", lit);
02239     if (!NIL_P(lit)) {
02240         hide_obj(lit);
02241         cnt++;
02242         ADD_INSN1(ret, nd_line(node), putobject, lit);
02243     }
02244 
02245     while (list) {
02246         node = list->nd_head;
02247         if (nd_type(node) == NODE_STR) {
02248             hide_obj(node->nd_lit);
02249             ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit);
02250         }
02251         else {
02252             COMPILE(ret, "each string", node);
02253         }
02254         cnt++;
02255         list = list->nd_next;
02256     }
02257     *cntp = cnt;
02258 
02259     return COMPILE_OK;
02260 }
02261 
02262 static int
02263 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
02264 {
02265     int cnt;
02266     compile_dstr_fragments(iseq, ret, node, &cnt);
02267     ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
02268     return COMPILE_OK;
02269 }
02270 
02271 static int
02272 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
02273 {
02274     int cnt;
02275     compile_dstr_fragments(iseq, ret, node, &cnt);
02276     ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
02277     return COMPILE_OK;
02278 }
02279 
02280 static int
02281 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
02282                          LABEL *then_label, LABEL *else_label)
02283 {
02284     switch (nd_type(cond)) {
02285       case NODE_AND:
02286         {
02287             LABEL *label = NEW_LABEL(nd_line(cond));
02288             compile_branch_condition(iseq, ret, cond->nd_1st, label,
02289                                      else_label);
02290             ADD_LABEL(ret, label);
02291             compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
02292                                      else_label);
02293             break;
02294         }
02295       case NODE_OR:
02296         {
02297             LABEL *label = NEW_LABEL(nd_line(cond));
02298             compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
02299                                      label);
02300             ADD_LABEL(ret, label);
02301             compile_branch_condition(iseq, ret, cond->nd_2nd, then_label,
02302                                      else_label);
02303             break;
02304         }
02305       case NODE_LIT:            /* NODE_LIT is always not true */
02306       case NODE_TRUE:
02307       case NODE_STR:
02308         /* printf("useless condition eliminate (%s)\n",  ruby_node_name(nd_type(cond))); */
02309         ADD_INSNL(ret, nd_line(cond), jump, then_label);
02310         break;
02311       case NODE_FALSE:
02312       case NODE_NIL:
02313         /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
02314         ADD_INSNL(ret, nd_line(cond), jump, else_label);
02315         break;
02316       default:
02317         COMPILE(ret, "branch condition", cond);
02318         ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
02319         ADD_INSNL(ret, nd_line(cond), jump, then_label);
02320         break;
02321     }
02322     return COMPILE_OK;
02323 }
02324 
02325 enum compile_array_type_t {
02326     COMPILE_ARRAY_TYPE_ARRAY,
02327     COMPILE_ARRAY_TYPE_HASH,
02328     COMPILE_ARRAY_TYPE_ARGS
02329 };
02330 
02331 static int
02332 compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
02333                enum compile_array_type_t type, int poped)
02334 {
02335     NODE *node = node_root;
02336     int line = (int)nd_line(node);
02337     int len = 0;
02338 
02339     if (nd_type(node) == NODE_ZARRAY) {
02340         if (!poped) {
02341             switch (type) {
02342               case COMPILE_ARRAY_TYPE_ARRAY: ADD_INSN1(ret, line, newarray, INT2FIX(0)); break;
02343               case COMPILE_ARRAY_TYPE_HASH: ADD_INSN1(ret, line, newhash, INT2FIX(0)); break;
02344               case COMPILE_ARRAY_TYPE_ARGS: /* do nothing */ break;
02345             }
02346         }
02347     }
02348     else {
02349         int opt_p = 1;
02350         int first = 1, i;
02351 
02352         while (node) {
02353             NODE *start_node = node, *end_node;
02354             NODE *kw = 0;
02355             const int max = 0x100;
02356             DECL_ANCHOR(anchor);
02357             INIT_ANCHOR(anchor);
02358 
02359             for (i=0; i<max && node; i++, len++, node = node->nd_next) {
02360                 if (CPDEBUG > 0 && nd_type(node) != NODE_ARRAY) {
02361                     rb_bug("compile_array: This node is not NODE_ARRAY, but %s", ruby_node_name(nd_type(node)));
02362                 }
02363 
02364                 if (type == COMPILE_ARRAY_TYPE_HASH && !node->nd_head) {
02365                     opt_p = 0;
02366                     kw = node->nd_next;
02367                     node = kw->nd_next;
02368                     kw = kw->nd_head;
02369                     break;
02370                 }
02371                 if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
02372                     opt_p = 0;
02373                 }
02374 
02375                 COMPILE_(anchor, "array element", node->nd_head, poped);
02376             }
02377 
02378             if (opt_p && type != COMPILE_ARRAY_TYPE_ARGS) {
02379                 if (!poped) {
02380                     VALUE ary = rb_ary_tmp_new(i);
02381 
02382                     end_node = node;
02383                     node = start_node;
02384 
02385                     while (node != end_node) {
02386                         rb_ary_push(ary, node->nd_head->nd_lit);
02387                         node = node->nd_next;
02388                     }
02389                     while (node && nd_type(node->nd_head) == NODE_LIT &&
02390                            node->nd_next && nd_type(node->nd_next->nd_head) == NODE_LIT) {
02391                         rb_ary_push(ary, node->nd_head->nd_lit);
02392                         node = node->nd_next;
02393                         rb_ary_push(ary, node->nd_head->nd_lit);
02394                         node = node->nd_next;
02395                         len++;
02396                     }
02397 
02398                     OBJ_FREEZE(ary);
02399 
02400                     iseq_add_mark_object_compile_time(iseq, ary);
02401 
02402                     if (first) {
02403                         first = 0;
02404                         if (type == COMPILE_ARRAY_TYPE_ARRAY) {
02405                             ADD_INSN1(ret, line, duparray, ary);
02406                         }
02407                         else { /* COMPILE_ARRAY_TYPE_HASH */
02408                             ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
02409                             ADD_INSN1(ret, line, putobject, ary);
02410                             ADD_SEND(ret, line, ID2SYM(id_core_hash_from_ary), INT2FIX(1));
02411                         }
02412                     }
02413                     else {
02414                         if (type == COMPILE_ARRAY_TYPE_ARRAY) {
02415                             ADD_INSN1(ret, line, putobject, ary);
02416                             ADD_INSN(ret, line, concatarray);
02417                         }
02418                         else {
02419                             ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
02420                             ADD_INSN1(ret, line, putobject, ary);
02421                             ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ary), INT2FIX(1));
02422                         }
02423                     }
02424                 }
02425             }
02426             else {
02427                 if (!poped) {
02428                     switch (type) {
02429                       case COMPILE_ARRAY_TYPE_ARRAY:
02430                         ADD_INSN1(anchor, line, newarray, INT2FIX(i));
02431 
02432                         if (first) {
02433                             first = 0;
02434                         }
02435                         else {
02436                             ADD_INSN(anchor, line, concatarray);
02437                         }
02438 
02439                         APPEND_LIST(ret, anchor);
02440                         break;
02441                       case COMPILE_ARRAY_TYPE_HASH:
02442                         if (first) {
02443                             first = 0;
02444                             ADD_INSN1(anchor, line, newhash, INT2FIX(i));
02445                             APPEND_LIST(ret, anchor);
02446                         }
02447                         else if (i > 0) {
02448                             ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
02449                             ADD_INSN(ret, line, swap);
02450                             APPEND_LIST(ret, anchor);
02451                             ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i + 1));
02452                         }
02453                         if (kw) {
02454                             ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
02455                             ADD_INSN(ret, line, swap);
02456                             COMPILE(ret, "keyword splat", kw);
02457                             ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_kwd), INT2FIX(2));
02458                         }
02459                         break;
02460                       case COMPILE_ARRAY_TYPE_ARGS:
02461                         APPEND_LIST(ret, anchor);
02462                         break;
02463                     }
02464                 }
02465                 else {
02466                     /* poped */
02467                     APPEND_LIST(ret, anchor);
02468                 }
02469             }
02470         }
02471     }
02472     return len;
02473 }
02474 
02475 static VALUE
02476 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, enum compile_array_type_t type)
02477 {
02478     return compile_array_(iseq, ret, node_root, type, 0);
02479 }
02480 
02481 static VALUE
02482 case_when_optimizable_literal(NODE * node)
02483 {
02484     switch (nd_type(node)) {
02485       case NODE_LIT: {
02486         VALUE v = node->nd_lit;
02487         double ival;
02488         if (RB_TYPE_P(v, T_FLOAT) &&
02489             modf(RFLOAT_VALUE(v), &ival) == 0.0) {
02490             return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
02491         }
02492         if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
02493             return v;
02494         }
02495         break;
02496       }
02497       case NODE_STR:
02498         return node->nd_lit;
02499     }
02500     return Qundef;
02501 }
02502 
02503 static int
02504 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
02505 {
02506     while (vals) {
02507         NODE* val = vals->nd_head;
02508         VALUE lit = case_when_optimizable_literal(val);
02509 
02510         if (lit == Qundef) {
02511             only_special_literals = 0;
02512         }
02513         else {
02514             if (rb_hash_lookup(literals, lit) != Qnil) {
02515                 rb_compile_warning(RSTRING_PTR(iseq->location.path), nd_line(val), "duplicated when clause is ignored");
02516             }
02517             else {
02518                 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
02519             }
02520         }
02521 
02522         ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
02523 
02524         if (nd_type(val) == NODE_STR) {
02525             debugp_param("nd_lit", val->nd_lit);
02526             OBJ_FREEZE(val->nd_lit);
02527             ADD_INSN1(cond_seq, nd_line(val), putobject, val->nd_lit);
02528         }
02529         else {
02530             COMPILE(cond_seq, "when cond", val);
02531         }
02532 
02533         ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
02534         ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
02535         vals = vals->nd_next;
02536     }
02537     return only_special_literals;
02538 }
02539 
02540 static int
02541 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
02542 {
02543     switch (nd_type(node)) {
02544       case NODE_ATTRASGN: {
02545         INSN *iobj;
02546         rb_call_info_t *ci;
02547         VALUE dupidx;
02548 
02549         COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node);
02550 
02551         POP_ELEMENT(ret);        /* pop pop insn */
02552         iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */
02553         ci = (rb_call_info_t *)iobj->operands[0];
02554         ci->orig_argc += 1; ci->argc = ci->orig_argc;
02555         dupidx = INT2FIX(ci->orig_argc);
02556 
02557         ADD_INSN1(ret, nd_line(node), topn, dupidx);
02558         ADD_ELEM(ret, (LINK_ELEMENT *)iobj);
02559         ADD_INSN(ret, nd_line(node), pop);      /* result */
02560         ADD_INSN(ret, nd_line(node), pop);      /* rhs    */
02561         break;
02562       }
02563       case NODE_MASGN: {
02564         DECL_ANCHOR(anchor);
02565         INIT_ANCHOR(anchor);
02566         COMPILE_POPED(anchor, "nest masgn lhs", node);
02567         REMOVE_ELEM(FIRST_ELEMENT(anchor));
02568         ADD_SEQ(ret, anchor);
02569         break;
02570       }
02571       default: {
02572         DECL_ANCHOR(anchor);
02573         INIT_ANCHOR(anchor);
02574         COMPILE_POPED(anchor, "masgn lhs", node);
02575         REMOVE_ELEM(FIRST_ELEMENT(anchor));
02576         ADD_SEQ(ret, anchor);
02577       }
02578     }
02579 
02580     return COMPILE_OK;
02581 }
02582 
02583 static void
02584 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn)
02585 {
02586     if (lhsn) {
02587         compile_massign_opt_lhs(iseq, ret, lhsn->nd_next);
02588         compile_massign_lhs(iseq, ret, lhsn->nd_head);
02589     }
02590 }
02591 
02592 static int
02593 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
02594                     NODE *rhsn, NODE *orig_lhsn)
02595 {
02596     VALUE mem[64];
02597     const int memsize = numberof(mem);
02598     int memindex = 0;
02599     int llen = 0, rlen = 0;
02600     int i;
02601     NODE *lhsn = orig_lhsn;
02602 
02603 #define MEMORY(v) { \
02604     int i; \
02605     if (memindex == memsize) return 0; \
02606     for (i=0; i<memindex; i++) { \
02607         if (mem[i] == (v)) return 0; \
02608     } \
02609     mem[memindex++] = (v); \
02610 }
02611 
02612     if (rhsn == 0 || nd_type(rhsn) != NODE_ARRAY) {
02613         return 0;
02614     }
02615 
02616     while (lhsn) {
02617         NODE *ln = lhsn->nd_head;
02618         switch (nd_type(ln)) {
02619           case NODE_LASGN:
02620             MEMORY(ln->nd_vid);
02621             break;
02622           case NODE_DASGN:
02623           case NODE_DASGN_CURR:
02624           case NODE_IASGN:
02625           case NODE_IASGN2:
02626           case NODE_CVASGN:
02627             MEMORY(ln->nd_vid);
02628             break;
02629           default:
02630             return 0;
02631         }
02632         lhsn = lhsn->nd_next;
02633         llen++;
02634     }
02635 
02636     while (rhsn) {
02637         if (llen <= rlen) {
02638             COMPILE_POPED(ret, "masgn val (popped)", rhsn->nd_head);
02639         }
02640         else {
02641             COMPILE(ret, "masgn val", rhsn->nd_head);
02642         }
02643         rhsn = rhsn->nd_next;
02644         rlen++;
02645     }
02646 
02647     if (llen > rlen) {
02648         for (i=0; i<llen-rlen; i++) {
02649             ADD_INSN(ret, nd_line(orig_lhsn), putnil);
02650         }
02651     }
02652 
02653     compile_massign_opt_lhs(iseq, ret, orig_lhsn);
02654     return 1;
02655 }
02656 
02657 static int
02658 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped)
02659 {
02660     NODE *rhsn = node->nd_value;
02661     NODE *splatn = node->nd_args;
02662     NODE *lhsn = node->nd_head;
02663     int lhs_splat = (splatn && (VALUE)splatn != (VALUE)-1) ? 1 : 0;
02664 
02665     if (!poped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
02666         int llen = 0;
02667         DECL_ANCHOR(lhsseq);
02668 
02669         INIT_ANCHOR(lhsseq);
02670 
02671         while (lhsn) {
02672             compile_massign_lhs(iseq, lhsseq, lhsn->nd_head);
02673             llen += 1;
02674             lhsn = lhsn->nd_next;
02675         }
02676 
02677         COMPILE(ret, "normal masgn rhs", rhsn);
02678 
02679         if (!poped) {
02680             ADD_INSN(ret, nd_line(node), dup);
02681         }
02682 
02683         ADD_INSN2(ret, nd_line(node), expandarray,
02684                   INT2FIX(llen), INT2FIX(lhs_splat));
02685         ADD_SEQ(ret, lhsseq);
02686 
02687         if (lhs_splat) {
02688             if (nd_type(splatn) == NODE_POSTARG) {
02689                 /*a, b, *r, p1, p2 */
02690                 NODE *postn = splatn->nd_2nd;
02691                 NODE *restn = splatn->nd_1st;
02692                 int num = (int)postn->nd_alen;
02693                 int flag = 0x02 | (((VALUE)restn == (VALUE)-1) ? 0x00 : 0x01);
02694 
02695                 ADD_INSN2(ret, nd_line(splatn), expandarray,
02696                           INT2FIX(num), INT2FIX(flag));
02697 
02698                 if ((VALUE)restn != (VALUE)-1) {
02699                     compile_massign_lhs(iseq, ret, restn);
02700                 }
02701                 while (postn) {
02702                     compile_massign_lhs(iseq, ret, postn->nd_head);
02703                     postn = postn->nd_next;
02704                 }
02705             }
02706             else {
02707                 /* a, b, *r */
02708                 compile_massign_lhs(iseq, ret, splatn);
02709             }
02710         }
02711     }
02712     return COMPILE_OK;
02713 }
02714 
02715 static int
02716 compile_colon2(rb_iseq_t *iseq, NODE * node,
02717                LINK_ANCHOR *pref, LINK_ANCHOR *body)
02718 {
02719     switch (nd_type(node)) {
02720       case NODE_CONST:
02721         debugi("compile_colon2 - colon", node->nd_vid);
02722         ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
02723         break;
02724       case NODE_COLON3:
02725         debugi("compile_colon2 - colon3", node->nd_mid);
02726         ADD_INSN(body, nd_line(node), pop);
02727         ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
02728         ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
02729         break;
02730       case NODE_COLON2:
02731         compile_colon2(iseq, node->nd_head, pref, body);
02732         debugi("compile_colon2 - colon2", node->nd_mid);
02733         ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
02734         break;
02735       default:
02736         COMPILE(pref, "const colon2 prefix", node);
02737         break;
02738     }
02739     return COMPILE_OK;
02740 }
02741 
02742 static VALUE
02743 compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
02744 {
02745     if (nd_type(cpath) == NODE_COLON3) {
02746         /* toplevel class ::Foo */
02747         ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
02748         return Qfalse;
02749     }
02750     else if (cpath->nd_head) {
02751         /* Bar::Foo */
02752         COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
02753         return Qfalse;
02754     }
02755     else {
02756         /* class at cbase Foo */
02757         ADD_INSN1(ret, nd_line(cpath), putspecialobject,
02758                   INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
02759         return Qtrue;
02760     }
02761 }
02762 
02763 #define defined_expr defined_expr0
02764 static int
02765 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
02766              NODE *node, LABEL **lfinish, VALUE needstr)
02767 {
02768     enum defined_type expr_type = 0;
02769     enum node_type type;
02770 
02771     switch (type = nd_type(node)) {
02772 
02773         /* easy literals */
02774       case NODE_NIL:
02775         expr_type = DEFINED_NIL;
02776         break;
02777       case NODE_SELF:
02778         expr_type = DEFINED_SELF;
02779         break;
02780       case NODE_TRUE:
02781         expr_type = DEFINED_TRUE;
02782         break;
02783       case NODE_FALSE:
02784         expr_type = DEFINED_FALSE;
02785         break;
02786 
02787       case NODE_ARRAY:{
02788         NODE *vals = node;
02789 
02790         do {
02791             defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
02792 
02793             if (!lfinish[1]) {
02794                 lfinish[1] = NEW_LABEL(nd_line(node));
02795             }
02796             ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
02797         } while ((vals = vals->nd_next) != NULL);
02798       }
02799       case NODE_STR:
02800       case NODE_LIT:
02801       case NODE_ZARRAY:
02802       case NODE_AND:
02803       case NODE_OR:
02804       default:
02805         expr_type = DEFINED_EXPR;
02806         break;
02807 
02808         /* variables */
02809       case NODE_LVAR:
02810       case NODE_DVAR:
02811         expr_type = DEFINED_LVAR;
02812         break;
02813 
02814       case NODE_IVAR:
02815         ADD_INSN(ret, nd_line(node), putnil);
02816         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR),
02817                   ID2SYM(node->nd_vid), needstr);
02818         return 1;
02819 
02820       case NODE_GVAR:
02821         ADD_INSN(ret, nd_line(node), putnil);
02822         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR),
02823                   ID2SYM(node->nd_entry->id), needstr);
02824         return 1;
02825 
02826       case NODE_CVAR:
02827         ADD_INSN(ret, nd_line(node), putnil);
02828         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR),
02829                   ID2SYM(node->nd_vid), needstr);
02830         return 1;
02831 
02832       case NODE_CONST:
02833         ADD_INSN(ret, nd_line(node), putnil);
02834         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
02835                   ID2SYM(node->nd_vid), needstr);
02836         return 1;
02837       case NODE_COLON2:
02838         if (!lfinish[1]) {
02839             lfinish[1] = NEW_LABEL(nd_line(node));
02840         }
02841         defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
02842         ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
02843 
02844         if (rb_is_const_id(node->nd_mid)) {
02845             COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
02846             ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
02847                       ID2SYM(node->nd_mid), needstr);
02848         }
02849         else {
02850             COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
02851             ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
02852                       ID2SYM(node->nd_mid), needstr);
02853         }
02854         return 1;
02855       case NODE_COLON3:
02856         ADD_INSN1(ret, nd_line(node), putobject, rb_cObject);
02857         ADD_INSN3(ret, nd_line(node), defined,
02858                   INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
02859         return 1;
02860 
02861         /* method dispatch */
02862       case NODE_CALL:
02863       case NODE_VCALL:
02864       case NODE_FCALL:
02865       case NODE_ATTRASGN:{
02866         int self = TRUE;
02867 
02868         switch (type) {
02869           case NODE_ATTRASGN:
02870             if (node->nd_recv == (NODE *)1) break;
02871           case NODE_CALL:
02872             self = FALSE;
02873             break;
02874           default:
02875             /* through */;
02876         }
02877         if (!lfinish[1]) {
02878             lfinish[1] = NEW_LABEL(nd_line(node));
02879         }
02880         if (node->nd_args) {
02881             defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
02882             ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
02883         }
02884         if (!self) {
02885             defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
02886             ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
02887             COMPILE(ret, "defined/recv", node->nd_recv);
02888             ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
02889                       ID2SYM(node->nd_mid), needstr);
02890         }
02891         else {
02892             ADD_INSN(ret, nd_line(node), putself);
02893             ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
02894                       ID2SYM(node->nd_mid), needstr);
02895         }
02896         return 1;
02897       }
02898 
02899       case NODE_YIELD:
02900         ADD_INSN(ret, nd_line(node), putnil);
02901         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0,
02902                   needstr);
02903         return 1;
02904 
02905       case NODE_BACK_REF:
02906       case NODE_NTH_REF:
02907         ADD_INSN(ret, nd_line(node), putnil);
02908         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
02909                   INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
02910                   needstr);
02911         return 1;
02912 
02913       case NODE_SUPER:
02914       case NODE_ZSUPER:
02915         ADD_INSN(ret, nd_line(node), putnil);
02916         ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
02917                   needstr);
02918         return 1;
02919 
02920       case NODE_OP_ASGN1:
02921       case NODE_OP_ASGN2:
02922       case NODE_OP_ASGN_OR:
02923       case NODE_OP_ASGN_AND:
02924       case NODE_MASGN:
02925       case NODE_LASGN:
02926       case NODE_DASGN:
02927       case NODE_DASGN_CURR:
02928       case NODE_GASGN:
02929       case NODE_IASGN:
02930       case NODE_CDECL:
02931       case NODE_CVDECL:
02932       case NODE_CVASGN:
02933         expr_type = DEFINED_ASGN;
02934         break;
02935     }
02936 
02937     if (expr_type) {
02938         if (needstr != Qfalse) {
02939             VALUE str = rb_iseq_defined_string(expr_type);
02940             ADD_INSN1(ret, nd_line(node), putobject, str);
02941         }
02942         else {
02943             ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
02944         }
02945         return 1;
02946     }
02947     return 0;
02948 }
02949 #undef defined_expr
02950 
02951 static int
02952 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
02953              NODE *node, LABEL **lfinish, VALUE needstr)
02954 {
02955     LINK_ELEMENT *lcur = ret->last;
02956     int done = defined_expr0(iseq, ret, node, lfinish, needstr);
02957     if (lfinish[1]) {
02958         int line = nd_line(node);
02959         LABEL *lstart = NEW_LABEL(line);
02960         LABEL *lend = NEW_LABEL(line);
02961         VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
02962                                          rb_str_concat(rb_str_new2
02963                                                        ("defined guard in "),
02964                                                        iseq->location.label),
02965                                          ISEQ_TYPE_DEFINED_GUARD, 0);
02966         APPEND_LABEL(ret, lcur, lstart);
02967         ADD_LABEL(ret, lend);
02968         ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
02969     }
02970     return done;
02971 }
02972 
02973 #define BUFSIZE 0x100
02974 
02975 static VALUE
02976 make_name_for_block(rb_iseq_t *iseq)
02977 {
02978     int level = 1;
02979     rb_iseq_t *ip = iseq;
02980 
02981     if (iseq->parent_iseq != 0) {
02982         while (ip->local_iseq != ip) {
02983             if (ip->type == ISEQ_TYPE_BLOCK) {
02984                 level++;
02985             }
02986             ip = ip->parent_iseq;
02987         }
02988     }
02989 
02990     if (level == 1) {
02991         return rb_sprintf("block in %s", RSTRING_PTR(ip->location.label));
02992     }
02993     else {
02994         return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->location.label));
02995     }
02996 }
02997 
02998 static void
02999 push_ensure_entry(rb_iseq_t *iseq,
03000                   struct iseq_compile_data_ensure_node_stack *enl,
03001                   struct ensure_range *er, NODE *node)
03002 {
03003     enl->ensure_node = node;
03004     enl->prev = iseq->compile_data->ensure_node_stack;  /* prev */
03005     enl->erange = er;
03006     iseq->compile_data->ensure_node_stack = enl;
03007 }
03008 
03009 static void
03010 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
03011                  LABEL *lstart, LABEL *lend)
03012 {
03013     struct ensure_range *ne =
03014         compile_data_alloc(iseq, sizeof(struct ensure_range));
03015 
03016     while (erange->next != 0) {
03017         erange = erange->next;
03018     }
03019     ne->next = 0;
03020     ne->begin = lend;
03021     ne->end = erange->end;
03022     erange->end = lstart;
03023 
03024     erange->next = ne;
03025 }
03026 
03027 static void
03028 add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq, int is_return)
03029 {
03030     struct iseq_compile_data_ensure_node_stack *enlp =
03031         iseq->compile_data->ensure_node_stack;
03032     struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
03033     DECL_ANCHOR(ensure);
03034 
03035     INIT_ANCHOR(ensure);
03036     while (enlp) {
03037         if (enlp->erange != 0) {
03038             DECL_ANCHOR(ensure_part);
03039             LABEL *lstart = NEW_LABEL(0);
03040             LABEL *lend = NEW_LABEL(0);
03041             INIT_ANCHOR(ensure_part);
03042 
03043             add_ensure_range(iseq, enlp->erange, lstart, lend);
03044 
03045             iseq->compile_data->ensure_node_stack = enlp->prev;
03046             ADD_LABEL(ensure_part, lstart);
03047             COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
03048             ADD_LABEL(ensure_part, lend);
03049             ADD_SEQ(ensure, ensure_part);
03050         }
03051         else {
03052             if (!is_return) {
03053                 break;
03054             }
03055         }
03056         enlp = enlp->prev;
03057     }
03058     iseq->compile_data->ensure_node_stack = prev_enlp;
03059     ADD_SEQ(ret, ensure);
03060 }
03061 
03062 static VALUE
03063 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, VALUE *flag)
03064 {
03065     VALUE argc = INT2FIX(0);
03066     int nsplat = 0;
03067     DECL_ANCHOR(arg_block);
03068     DECL_ANCHOR(args_splat);
03069 
03070     INIT_ANCHOR(arg_block);
03071     INIT_ANCHOR(args_splat);
03072     if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
03073         COMPILE(arg_block, "block", argn->nd_body);
03074         *flag |= VM_CALL_ARGS_BLOCKARG;
03075         argn = argn->nd_head;
03076     }
03077 
03078   setup_argn:
03079     if (argn) {
03080         switch (nd_type(argn)) {
03081           case NODE_SPLAT: {
03082             COMPILE(args, "args (splat)", argn->nd_head);
03083             argc = INT2FIX(1);
03084             nsplat++;
03085             *flag |= VM_CALL_ARGS_SPLAT;
03086             break;
03087           }
03088           case NODE_ARGSCAT:
03089           case NODE_ARGSPUSH: {
03090             int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
03091             DECL_ANCHOR(tmp);
03092 
03093             INIT_ANCHOR(tmp);
03094             COMPILE(tmp, "args (cat: splat)", argn->nd_body);
03095             if (next_is_array && nsplat == 0) {
03096                 /* none */
03097             }
03098             else {
03099                 if (nd_type(argn) == NODE_ARGSCAT) {
03100                     ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
03101                 }
03102                 else {
03103                     ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1));
03104                 }
03105             }
03106             INSERT_LIST(args_splat, tmp);
03107             nsplat++;
03108             *flag |= VM_CALL_ARGS_SPLAT;
03109 
03110             if (next_is_array) {
03111                 argc = INT2FIX(compile_array(iseq, args, argn->nd_head, COMPILE_ARRAY_TYPE_ARGS) + 1);
03112             }
03113             else {
03114                 argn = argn->nd_head;
03115                 goto setup_argn;
03116             }
03117             break;
03118           }
03119           case NODE_ARRAY: {
03120             argc = INT2FIX(compile_array(iseq, args, argn, COMPILE_ARRAY_TYPE_ARGS));
03121             break;
03122           }
03123           default: {
03124             rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn)));
03125           }
03126         }
03127     }
03128 
03129     if (nsplat > 1) {
03130         int i;
03131         for (i=1; i<nsplat; i++) {
03132             ADD_INSN(args_splat, nd_line(args), concatarray);
03133         }
03134     }
03135 
03136     if (!LIST_SIZE_ZERO(args_splat)) {
03137         ADD_SEQ(args, args_splat);
03138     }
03139 
03140     if (*flag & VM_CALL_ARGS_BLOCKARG) {
03141         ADD_SEQ(args, arg_block);
03142     }
03143     return argc;
03144 }
03145 
03146 
03154 static int
03155 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
03156 {
03157     enum node_type type;
03158     int line;
03159 
03160     if (node == 0) {
03161         if (!poped) {
03162             debugs("node: NODE_NIL(implicit)\n");
03163             ADD_INSN(ret, iseq->compile_data->last_line, putnil);
03164         }
03165         return COMPILE_OK;
03166     }
03167 
03168     iseq->compile_data->last_line = line = (int)nd_line(node);
03169     debug_node_start(node);
03170 
03171     type = nd_type(node);
03172 
03173     if (node->flags & NODE_FL_NEWLINE) {
03174         ADD_TRACE(ret, line, RUBY_EVENT_LINE);
03175     }
03176 
03177     switch (type) {
03178       case NODE_BLOCK:{
03179         while (node && nd_type(node) == NODE_BLOCK) {
03180             COMPILE_(ret, "BLOCK body", node->nd_head,
03181                      (node->nd_next == 0 && poped == 0) ? 0 : 1);
03182             node = node->nd_next;
03183         }
03184         if (node) {
03185             COMPILE_(ret, "BLOCK next", node->nd_next, poped);
03186         }
03187         break;
03188       }
03189       case NODE_IF:{
03190         DECL_ANCHOR(cond_seq);
03191         DECL_ANCHOR(then_seq);
03192         DECL_ANCHOR(else_seq);
03193         LABEL *then_label, *else_label, *end_label;
03194 
03195         INIT_ANCHOR(cond_seq);
03196         INIT_ANCHOR(then_seq);
03197         INIT_ANCHOR(else_seq);
03198         then_label = NEW_LABEL(line);
03199         else_label = NEW_LABEL(line);
03200         end_label = NEW_LABEL(line);
03201 
03202         compile_branch_condition(iseq, cond_seq, node->nd_cond,
03203                                  then_label, else_label);
03204         COMPILE_(then_seq, "then", node->nd_body, poped);
03205         COMPILE_(else_seq, "else", node->nd_else, poped);
03206 
03207         ADD_SEQ(ret, cond_seq);
03208 
03209         ADD_LABEL(ret, then_label);
03210         ADD_SEQ(ret, then_seq);
03211         ADD_INSNL(ret, line, jump, end_label);
03212 
03213         ADD_LABEL(ret, else_label);
03214         ADD_SEQ(ret, else_seq);
03215 
03216         ADD_LABEL(ret, end_label);
03217 
03218         break;
03219       }
03220       case NODE_CASE:{
03221         NODE *vals;
03222         NODE *tempnode = node;
03223         LABEL *endlabel, *elselabel;
03224         DECL_ANCHOR(head);
03225         DECL_ANCHOR(body_seq);
03226         DECL_ANCHOR(cond_seq);
03227         int only_special_literals = 1;
03228         VALUE literals = rb_hash_new();
03229 
03230         INIT_ANCHOR(head);
03231         INIT_ANCHOR(body_seq);
03232         INIT_ANCHOR(cond_seq);
03233 
03234         RHASH_TBL(literals)->type = &cdhash_type;
03235 
03236         if (node->nd_head == 0) {
03237             COMPILE_(ret, "when", node->nd_body, poped);
03238             break;
03239         }
03240         COMPILE(head, "case base", node->nd_head);
03241 
03242         node = node->nd_body;
03243         type = nd_type(node);
03244         line = nd_line(node);
03245 
03246         if (type != NODE_WHEN) {
03247             COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
03248         }
03249 
03250         endlabel = NEW_LABEL(line);
03251         elselabel = NEW_LABEL(line);
03252 
03253         ADD_SEQ(ret, head);     /* case VAL */
03254 
03255         while (type == NODE_WHEN) {
03256             LABEL *l1;
03257 
03258             l1 = NEW_LABEL(line);
03259             ADD_LABEL(body_seq, l1);
03260             ADD_INSN(body_seq, line, pop);
03261             COMPILE_(body_seq, "when body", node->nd_body, poped);
03262             ADD_INSNL(body_seq, line, jump, endlabel);
03263 
03264             vals = node->nd_head;
03265             if (vals) {
03266                 switch (nd_type(vals)) {
03267                   case NODE_ARRAY:
03268                     only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
03269                     break;
03270                   case NODE_SPLAT:
03271                   case NODE_ARGSCAT:
03272                   case NODE_ARGSPUSH:
03273                     only_special_literals = 0;
03274                     ADD_INSN (cond_seq, nd_line(vals), dup);
03275                     COMPILE(cond_seq, "when/cond splat", vals);
03276                     ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
03277                     ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
03278                     break;
03279                   default:
03280                     rb_bug("NODE_CASE: unknown node (%s)",
03281                            ruby_node_name(nd_type(vals)));
03282                 }
03283             }
03284             else {
03285                 rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
03286             }
03287 
03288             node = node->nd_next;
03289             if (!node) {
03290                 break;
03291             }
03292             type = nd_type(node);
03293             line = nd_line(node);
03294         }
03295         /* else */
03296         if (node) {
03297             ADD_LABEL(cond_seq, elselabel);
03298             ADD_INSN(cond_seq, line, pop);
03299             COMPILE_(cond_seq, "else", node, poped);
03300             ADD_INSNL(cond_seq, line, jump, endlabel);
03301         }
03302         else {
03303             debugs("== else (implicit)\n");
03304             ADD_LABEL(cond_seq, elselabel);
03305             ADD_INSN(cond_seq, nd_line(tempnode), pop);
03306             if (!poped) {
03307                 ADD_INSN(cond_seq, nd_line(tempnode), putnil);
03308             }
03309             ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
03310         }
03311 
03312         if (only_special_literals) {
03313             iseq_add_mark_object(iseq, literals);
03314 
03315             ADD_INSN(ret, nd_line(tempnode), dup);
03316             ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, literals, elselabel);
03317         }
03318 
03319         ADD_SEQ(ret, cond_seq);
03320         ADD_SEQ(ret, body_seq);
03321         ADD_LABEL(ret, endlabel);
03322         break;
03323       }
03324       case NODE_WHEN:{
03325         NODE *vals;
03326         NODE *val;
03327         NODE *orig_node = node;
03328         LABEL *endlabel;
03329         DECL_ANCHOR(body_seq);
03330 
03331         INIT_ANCHOR(body_seq);
03332         endlabel = NEW_LABEL(line);
03333 
03334         while (node && nd_type(node) == NODE_WHEN) {
03335             LABEL *l1 = NEW_LABEL(line = nd_line(node));
03336             ADD_LABEL(body_seq, l1);
03337             COMPILE_(body_seq, "when", node->nd_body, poped);
03338             ADD_INSNL(body_seq, line, jump, endlabel);
03339 
03340             vals = node->nd_head;
03341             if (!vals) {
03342                 rb_bug("NODE_WHEN: must be NODE_ARRAY, but 0");
03343             }
03344             switch (nd_type(vals)) {
03345               case NODE_ARRAY:
03346                 while (vals) {
03347                     val = vals->nd_head;
03348                     COMPILE(ret, "when2", val);
03349                     ADD_INSNL(ret, nd_line(val), branchif, l1);
03350                     vals = vals->nd_next;
03351                 }
03352                 break;
03353               case NODE_SPLAT:
03354               case NODE_ARGSCAT:
03355               case NODE_ARGSPUSH:
03356                 ADD_INSN(ret, nd_line(vals), putnil);
03357                 COMPILE(ret, "when2/cond splat", vals);
03358                 ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
03359                 ADD_INSNL(ret, nd_line(vals), branchif, l1);
03360                 break;
03361               default:
03362                 rb_bug("NODE_WHEN: unknown node (%s)",
03363                        ruby_node_name(nd_type(vals)));
03364             }
03365             node = node->nd_next;
03366         }
03367         /* else */
03368         COMPILE_(ret, "else", node, poped);
03369         ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
03370 
03371         ADD_SEQ(ret, body_seq);
03372         ADD_LABEL(ret, endlabel);
03373 
03374         break;
03375       }
03376       case NODE_OPT_N:
03377       case NODE_WHILE:
03378       case NODE_UNTIL:{
03379         LABEL *prev_start_label = iseq->compile_data->start_label;
03380         LABEL *prev_end_label = iseq->compile_data->end_label;
03381         LABEL *prev_redo_label = iseq->compile_data->redo_label;
03382         int prev_loopval_popped = iseq->compile_data->loopval_popped;
03383 
03384         struct iseq_compile_data_ensure_node_stack enl;
03385 
03386         LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(line);  /* next  */
03387         LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(line);   /* redo  */
03388         LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line);   /* break */
03389         LABEL *end_label = NEW_LABEL(line);
03390 
03391         LABEL *next_catch_label = NEW_LABEL(line);
03392         LABEL *tmp_label = NULL;
03393 
03394         iseq->compile_data->loopval_popped = 0;
03395         push_ensure_entry(iseq, &enl, 0, 0);
03396 
03397         if (type == NODE_OPT_N || node->nd_state == 1) {
03398             ADD_INSNL(ret, line, jump, next_label);
03399         }
03400         else {
03401             tmp_label = NEW_LABEL(line);
03402             ADD_INSNL(ret, line, jump, tmp_label);
03403         }
03404         ADD_INSN(ret, line, putnil);
03405         ADD_LABEL(ret, next_catch_label);
03406         ADD_INSN(ret, line, pop);
03407         ADD_INSNL(ret, line, jump, next_label);
03408         if (tmp_label) ADD_LABEL(ret, tmp_label);
03409 
03410         ADD_LABEL(ret, redo_label);
03411         COMPILE_POPED(ret, "while body", node->nd_body);
03412         ADD_LABEL(ret, next_label);     /* next */
03413 
03414         if (type == NODE_WHILE) {
03415             compile_branch_condition(iseq, ret, node->nd_cond,
03416                                      redo_label, end_label);
03417         }
03418         else if (type == NODE_UNTIL) {
03419             /* untile */
03420             compile_branch_condition(iseq, ret, node->nd_cond,
03421                                      end_label, redo_label);
03422         }
03423         else {
03424             ADD_CALL_RECEIVER(ret, line);
03425             ADD_CALL(ret, line, ID2SYM(idGets), INT2FIX(0));
03426             ADD_INSNL(ret, line, branchif, redo_label);
03427             /* opt_n */
03428         }
03429 
03430         ADD_LABEL(ret, end_label);
03431 
03432         if (node->nd_state == Qundef) {
03433             /* ADD_INSN(ret, line, putundef); */
03434             rb_bug("unsupported: putundef");
03435         }
03436         else {
03437             ADD_INSN(ret, line, putnil);
03438         }
03439 
03440         ADD_LABEL(ret, break_label);    /* break */
03441 
03442         if (poped) {
03443             ADD_INSN(ret, line, pop);
03444         }
03445 
03446         ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
03447                         0, break_label);
03448         ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, 0,
03449                         next_catch_label);
03450         ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
03451                         iseq->compile_data->redo_label);
03452 
03453         iseq->compile_data->start_label = prev_start_label;
03454         iseq->compile_data->end_label = prev_end_label;
03455         iseq->compile_data->redo_label = prev_redo_label;
03456         iseq->compile_data->loopval_popped = prev_loopval_popped;
03457         iseq->compile_data->ensure_node_stack = iseq->compile_data->ensure_node_stack->prev;
03458         break;
03459       }
03460       case NODE_ITER:
03461       case NODE_FOR:{
03462         VALUE prevblock = iseq->compile_data->current_block;
03463         LABEL *retry_label = NEW_LABEL(line);
03464         LABEL *retry_end_l = NEW_LABEL(line);
03465 
03466         ADD_LABEL(ret, retry_label);
03467         if (nd_type(node) == NODE_FOR) {
03468             COMPILE(ret, "iter caller (for)", node->nd_iter);
03469 
03470             iseq->compile_data->current_block =
03471                 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
03472                                   ISEQ_TYPE_BLOCK, line);
03473 
03474             ADD_SEND_R(ret, line, ID2SYM(idEach), INT2FIX(0),
03475                        iseq->compile_data->current_block, INT2FIX(0));
03476         }
03477         else {
03478             iseq->compile_data->current_block =
03479                 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
03480                                   ISEQ_TYPE_BLOCK, line);
03481             COMPILE(ret, "iter caller", node->nd_iter);
03482         }
03483         ADD_LABEL(ret, retry_end_l);
03484 
03485         if (poped) {
03486             ADD_INSN(ret, line, pop);
03487         }
03488 
03489         iseq->compile_data->current_block = prevblock;
03490 
03491         ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
03492 
03493         break;
03494       }
03495       case NODE_BREAK:{
03496         unsigned long level = 0;
03497 
03498         if (iseq->compile_data->redo_label != 0) {
03499             /* while/until */
03500             LABEL *splabel = NEW_LABEL(0);
03501             ADD_LABEL(ret, splabel);
03502             ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03503             COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
03504             add_ensure_iseq(ret, iseq, 0);
03505             ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
03506             ADD_ADJUST_RESTORE(ret, splabel);
03507 
03508             if (!poped) {
03509                 ADD_INSN(ret, line, putnil);
03510             }
03511         }
03512         else if (iseq->type == ISEQ_TYPE_BLOCK) {
03513           break_by_insn:
03514             /* escape from block */
03515             COMPILE(ret, "break val (block)", node->nd_stts);
03516             ADD_INSN1(ret, line, throw, INT2FIX(level | 0x02) /* TAG_BREAK */ );
03517             if (poped) {
03518                 ADD_INSN(ret, line, pop);
03519             }
03520         }
03521         else if (iseq->type == ISEQ_TYPE_EVAL) {
03522           break_in_eval:
03523             COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
03524         }
03525         else {
03526             rb_iseq_t *ip = iseq->parent_iseq;
03527             while (ip) {
03528                 if (!ip->compile_data) {
03529                     ip = 0;
03530                     break;
03531                 }
03532 
03533                 level++;
03534                 if (ip->compile_data->redo_label != 0) {
03535                     level = 0x8000;
03536                     if (ip->compile_data->loopval_popped == 0) {
03537                         /* need value */
03538                         level |= 0x4000;
03539                     }
03540                     goto break_by_insn;
03541                 }
03542                 else if (ip->type == ISEQ_TYPE_BLOCK) {
03543                     level <<= 16;
03544                     goto break_by_insn;
03545                 }
03546                 else if (ip->type == ISEQ_TYPE_EVAL) {
03547                     goto break_in_eval;
03548                 }
03549 
03550                 ip = ip->parent_iseq;
03551             }
03552             COMPILE_ERROR((ERROR_ARGS "Invalid break"));
03553         }
03554         break;
03555       }
03556       case NODE_NEXT:{
03557         unsigned long level = 0;
03558 
03559         if (iseq->compile_data->redo_label != 0) {
03560             LABEL *splabel = NEW_LABEL(0);
03561             debugs("next in while loop\n");
03562             ADD_LABEL(ret, splabel);
03563             COMPILE(ret, "next val/valid syntax?", node->nd_stts);
03564             add_ensure_iseq(ret, iseq, 0);
03565             ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03566             ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
03567             ADD_ADJUST_RESTORE(ret, splabel);
03568             if (!poped) {
03569                 ADD_INSN(ret, line, putnil);
03570             }
03571         }
03572         else if (iseq->compile_data->end_label) {
03573             LABEL *splabel = NEW_LABEL(0);
03574             debugs("next in block\n");
03575             ADD_LABEL(ret, splabel);
03576             ADD_ADJUST(ret, line, iseq->compile_data->start_label);
03577             COMPILE(ret, "next val", node->nd_stts);
03578             add_ensure_iseq(ret, iseq, 0);
03579             ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
03580             ADD_ADJUST_RESTORE(ret, splabel);
03581 
03582             if (!poped) {
03583                 ADD_INSN(ret, line, putnil);
03584             }
03585         }
03586         else if (iseq->type == ISEQ_TYPE_EVAL) {
03587           next_in_eval:
03588             COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
03589         }
03590         else {
03591             rb_iseq_t *ip;
03592             ip = iseq;
03593             while (ip) {
03594                 if (!ip->compile_data) {
03595                     ip = 0;
03596                     break;
03597                 }
03598 
03599                 level = 0x8000 | 0x4000;
03600                 if (ip->compile_data->redo_label != 0) {
03601                     /* while loop */
03602                     break;
03603                 }
03604                 else if (ip->type == ISEQ_TYPE_BLOCK) {
03605                     break;
03606                 }
03607                 else if (ip->type == ISEQ_TYPE_EVAL) {
03608                     goto next_in_eval;
03609                 }
03610 
03611                 ip = ip->parent_iseq;
03612             }
03613             if (ip != 0) {
03614                 COMPILE(ret, "next val", node->nd_stts);
03615                 ADD_INSN1(ret, line, throw, INT2FIX(level | 0x03) /* TAG_NEXT */ );
03616 
03617                 if (poped) {
03618                     ADD_INSN(ret, line, pop);
03619                 }
03620             }
03621             else {
03622                 COMPILE_ERROR((ERROR_ARGS "Invalid next"));
03623             }
03624         }
03625         break;
03626       }
03627       case NODE_REDO:{
03628         if (iseq->compile_data->redo_label) {
03629             LABEL *splabel = NEW_LABEL(0);
03630             debugs("redo in while");
03631             ADD_LABEL(ret, splabel);
03632             ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03633             add_ensure_iseq(ret, iseq, 0);
03634             ADD_INSNL(ret, line, jump, iseq->compile_data->redo_label);
03635             ADD_ADJUST_RESTORE(ret, splabel);
03636             if (!poped) {
03637                 ADD_INSN(ret, line, putnil);
03638             }
03639         }
03640         else if (iseq->type == ISEQ_TYPE_EVAL) {
03641           redo_in_eval:
03642             COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
03643         }
03644         else if (iseq->compile_data->start_label) {
03645             LABEL *splabel = NEW_LABEL(0);
03646 
03647             debugs("redo in block");
03648             ADD_LABEL(ret, splabel);
03649             add_ensure_iseq(ret, iseq, 0);
03650             ADD_ADJUST(ret, line, iseq->compile_data->start_label);
03651             ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
03652             ADD_ADJUST_RESTORE(ret, splabel);
03653 
03654             if (!poped) {
03655                 ADD_INSN(ret, line, putnil);
03656             }
03657         }
03658         else {
03659             rb_iseq_t *ip;
03660             unsigned long level;
03661             level = 0x8000 | 0x4000;
03662             ip = iseq;
03663             while (ip) {
03664                 if (!ip->compile_data) {
03665                     ip = 0;
03666                     break;
03667                 }
03668 
03669                 if (ip->compile_data->redo_label != 0) {
03670                     break;
03671                 }
03672                 else if (ip->type == ISEQ_TYPE_BLOCK) {
03673                     break;
03674                 }
03675                 else if (ip->type == ISEQ_TYPE_EVAL) {
03676                     goto redo_in_eval;
03677                 }
03678 
03679                 ip = ip->parent_iseq;
03680             }
03681             if (ip != 0) {
03682                 ADD_INSN(ret, line, putnil);
03683                 ADD_INSN1(ret, line, throw, INT2FIX(level | 0x05) /* TAG_REDO */ );
03684 
03685                 if (poped) {
03686                     ADD_INSN(ret, line, pop);
03687                 }
03688             }
03689             else {
03690                 COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
03691             }
03692         }
03693         break;
03694       }
03695       case NODE_RETRY:{
03696         if (iseq->type == ISEQ_TYPE_RESCUE) {
03697             ADD_INSN(ret, line, putnil);
03698             ADD_INSN1(ret, line, throw, INT2FIX(0x04) /* TAG_RETRY */ );
03699 
03700             if (poped) {
03701                 ADD_INSN(ret, line, pop);
03702             }
03703         }
03704         else {
03705             COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
03706         }
03707         break;
03708       }
03709       case NODE_BEGIN:{
03710         COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
03711         break;
03712       }
03713       case NODE_RESCUE:{
03714         LABEL *lstart = NEW_LABEL(line);
03715         LABEL *lend = NEW_LABEL(line);
03716         LABEL *lcont = NEW_LABEL(line);
03717         VALUE rescue = NEW_CHILD_ISEQVAL(
03718             node->nd_resq,
03719             rb_str_concat(rb_str_new2("rescue in "), iseq->location.label),
03720             ISEQ_TYPE_RESCUE, line);
03721 
03722         ADD_LABEL(ret, lstart);
03723         COMPILE(ret, "rescue head", node->nd_head);
03724         ADD_LABEL(ret, lend);
03725         if (node->nd_else) {
03726             ADD_INSN(ret, line, pop);
03727             COMPILE(ret, "rescue else", node->nd_else);
03728         }
03729         ADD_INSN(ret, line, nop);
03730         ADD_LABEL(ret, lcont);
03731 
03732         if (poped) {
03733             ADD_INSN(ret, line, pop);
03734         }
03735 
03736         /* register catch entry */
03737         ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
03738         ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
03739         break;
03740       }
03741       case NODE_RESBODY:{
03742         NODE *resq = node;
03743         NODE *narg;
03744         LABEL *label_miss, *label_hit;
03745 
03746         while (resq) {
03747             label_miss = NEW_LABEL(line);
03748             label_hit = NEW_LABEL(line);
03749 
03750             narg = resq->nd_args;
03751             if (narg) {
03752                 switch (nd_type(narg)) {
03753                   case NODE_ARRAY:
03754                     while (narg) {
03755                         ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03756                         COMPILE(ret, "rescue arg", narg->nd_head);
03757                         ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
03758                         ADD_INSNL(ret, line, branchif, label_hit);
03759                         narg = narg->nd_next;
03760                     }
03761                     break;
03762                   case NODE_SPLAT:
03763                   case NODE_ARGSCAT:
03764                   case NODE_ARGSPUSH:
03765                     ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03766                     COMPILE(ret, "rescue/cond splat", narg);
03767                     ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
03768                     ADD_INSNL(ret, line, branchif, label_hit);
03769                     break;
03770                   default:
03771                     rb_bug("NODE_RESBODY: unknown node (%s)",
03772                            ruby_node_name(nd_type(narg)));
03773                 }
03774             }
03775             else {
03776                 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03777                 ADD_INSN1(ret, line, putobject, rb_eStandardError);
03778                 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
03779                 ADD_INSNL(ret, line, branchif, label_hit);
03780             }
03781             ADD_INSNL(ret, line, jump, label_miss);
03782             ADD_LABEL(ret, label_hit);
03783             COMPILE(ret, "resbody body", resq->nd_body);
03784             if (iseq->compile_data->option->tailcall_optimization) {
03785                 ADD_INSN(ret, line, nop);
03786             }
03787             ADD_INSN(ret, line, leave);
03788             ADD_LABEL(ret, label_miss);
03789             resq = resq->nd_head;
03790         }
03791         break;
03792       }
03793       case NODE_ENSURE:{
03794         DECL_ANCHOR(ensr);
03795         VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
03796                                          rb_str_concat(rb_str_new2
03797                                                        ("ensure in "),
03798                                                        iseq->location.label),
03799                                          ISEQ_TYPE_ENSURE, line);
03800         LABEL *lstart = NEW_LABEL(line);
03801         LABEL *lend = NEW_LABEL(line);
03802         LABEL *lcont = NEW_LABEL(line);
03803         struct ensure_range er;
03804         struct iseq_compile_data_ensure_node_stack enl;
03805         struct ensure_range *erange;
03806 
03807         INIT_ANCHOR(ensr);
03808         COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
03809 
03810         er.begin = lstart;
03811         er.end = lend;
03812         er.next = 0;
03813         push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
03814 
03815         ADD_LABEL(ret, lstart);
03816         COMPILE_(ret, "ensure head", node->nd_head, poped);
03817         ADD_LABEL(ret, lend);
03818         if (ensr->anchor.next == 0) {
03819             ADD_INSN(ret, line, nop);
03820         }
03821         else {
03822             ADD_SEQ(ret, ensr);
03823         }
03824         ADD_LABEL(ret, lcont);
03825 
03826         erange = iseq->compile_data->ensure_node_stack->erange;
03827         while (erange) {
03828             ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
03829                             ensure, lcont);
03830             erange = erange->next;
03831         }
03832 
03833         iseq->compile_data->ensure_node_stack = enl.prev;
03834         break;
03835       }
03836 
03837       case NODE_AND:
03838       case NODE_OR:{
03839         LABEL *end_label = NEW_LABEL(line);
03840         COMPILE(ret, "nd_1st", node->nd_1st);
03841         if (!poped) {
03842             ADD_INSN(ret, line, dup);
03843         }
03844         if (type == NODE_AND) {
03845             ADD_INSNL(ret, line, branchunless, end_label);
03846         }
03847         else {
03848             ADD_INSNL(ret, line, branchif, end_label);
03849         }
03850         if (!poped) {
03851             ADD_INSN(ret, line, pop);
03852         }
03853         COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
03854         ADD_LABEL(ret, end_label);
03855         break;
03856       }
03857 
03858       case NODE_MASGN:{
03859         compile_massign(iseq, ret, node, poped);
03860         break;
03861       }
03862 
03863       case NODE_LASGN:{
03864         ID id = node->nd_vid;
03865         int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
03866 
03867         debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
03868         COMPILE(ret, "rvalue", node->nd_value);
03869 
03870         if (!poped) {
03871             ADD_INSN(ret, line, dup);
03872         }
03873         ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
03874 
03875         break;
03876       }
03877       case NODE_DASGN:
03878       case NODE_DASGN_CURR:{
03879         int idx, lv, ls;
03880         COMPILE(ret, "dvalue", node->nd_value);
03881         debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
03882 
03883         if (!poped) {
03884             ADD_INSN(ret, line, dup);
03885         }
03886 
03887         idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
03888 
03889         if (idx < 0) {
03890             rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
03891         }
03892 
03893         ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
03894         break;
03895       }
03896       case NODE_GASGN:{
03897         COMPILE(ret, "lvalue", node->nd_value);
03898 
03899         if (!poped) {
03900             ADD_INSN(ret, line, dup);
03901         }
03902         ADD_INSN1(ret, line, setglobal,
03903                   ((VALUE)node->nd_entry | 1));
03904         break;
03905       }
03906       case NODE_IASGN:
03907       case NODE_IASGN2:{
03908         COMPILE(ret, "lvalue", node->nd_value);
03909         if (!poped) {
03910             ADD_INSN(ret, line, dup);
03911         }
03912         ADD_INSN2(ret, line, setinstancevariable,
03913                   ID2SYM(node->nd_vid), INT2FIX(iseq->ic_size++));
03914         break;
03915       }
03916       case NODE_CDECL:{
03917         COMPILE(ret, "lvalue", node->nd_value);
03918 
03919         if (!poped) {
03920             ADD_INSN(ret, line, dup);
03921         }
03922 
03923         if (node->nd_vid) {
03924             ADD_INSN1(ret, line, putspecialobject,
03925                       INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
03926             ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
03927         }
03928         else {
03929             compile_cpath(ret, iseq, node->nd_else);
03930             ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
03931         }
03932         break;
03933       }
03934       case NODE_CVASGN:{
03935         COMPILE(ret, "cvasgn val", node->nd_value);
03936         if (!poped) {
03937             ADD_INSN(ret, line, dup);
03938         }
03939         ADD_INSN1(ret, line, setclassvariable,
03940                   ID2SYM(node->nd_vid));
03941         break;
03942       }
03943       case NODE_OP_ASGN1: {
03944         DECL_ANCHOR(args);
03945         VALUE argc;
03946         VALUE flag = 0;
03947         ID id = node->nd_mid;
03948         int boff = 0;
03949 
03950         /*
03951          * a[x] (op)= y
03952          *
03953          * nil       # nil
03954          * eval a    # nil a
03955          * eval x    # nil a x
03956          * dupn 2    # nil a x a x
03957          * send :[]  # nil a x a[x]
03958          * eval y    # nil a x a[x] y
03959          * send op   # nil a x ret
03960          * setn 3    # ret a x ret
03961          * send []=  # ret ?
03962          * pop       # ret
03963          */
03964 
03965         /*
03966          * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
03967          * NODE_OP_ASGN nd_recv
03968          *              nd_args->nd_head
03969          *              nd_args->nd_body
03970          *              nd_mid
03971          */
03972 
03973         if (!poped) {
03974             ADD_INSN(ret, line, putnil);
03975         }
03976         COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
03977         switch (nd_type(node->nd_args->nd_head)) {
03978           case NODE_ZARRAY:
03979             argc = INT2FIX(0);
03980             break;
03981           case NODE_BLOCK_PASS:
03982             boff = 1;
03983           default:
03984             INIT_ANCHOR(args);
03985             argc = setup_args(iseq, args, node->nd_args->nd_head, &flag);
03986             ADD_SEQ(ret, args);
03987         }
03988         ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
03989         ADD_SEND_R(ret, line, ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
03990 
03991         if (id == 0 || id == 1) {
03992             /* 0: or, 1: and
03993                a[x] ||= y
03994 
03995                unless/if a[x]
03996                a[x]= y
03997                else
03998                nil
03999                end
04000             */
04001             LABEL *label = NEW_LABEL(line);
04002             LABEL *lfin = NEW_LABEL(line);
04003 
04004             ADD_INSN(ret, line, dup);
04005             if (id == 0) {
04006                 /* or */
04007                 ADD_INSNL(ret, line, branchif, label);
04008             }
04009             else {
04010                 /* and */
04011                 ADD_INSNL(ret, line, branchunless, label);
04012             }
04013             ADD_INSN(ret, line, pop);
04014 
04015             COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
04016             if (!poped) {
04017                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04018             }
04019             if (flag & VM_CALL_ARGS_SPLAT) {
04020                 ADD_INSN1(ret, line, newarray, INT2FIX(1));
04021                 if (boff > 0) {
04022                     ADD_INSN1(ret, line, dupn, INT2FIX(3));
04023                     ADD_INSN(ret, line, swap);
04024                     ADD_INSN(ret, line, pop);
04025                 }
04026                 ADD_INSN(ret, line, concatarray);
04027                 if (boff > 0) {
04028                     ADD_INSN1(ret, line, setn, INT2FIX(3));
04029                     ADD_INSN(ret, line, pop);
04030                     ADD_INSN(ret, line, pop);
04031                 }
04032                 ADD_SEND_R(ret, line, ID2SYM(idASET),
04033                            argc, Qfalse, LONG2FIX(flag));
04034             }
04035             else {
04036                 if (boff > 0)
04037                     ADD_INSN(ret, line, swap);
04038                 ADD_SEND_R(ret, line, ID2SYM(idASET),
04039                            FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
04040             }
04041             ADD_INSN(ret, line, pop);
04042             ADD_INSNL(ret, line, jump, lfin);
04043             ADD_LABEL(ret, label);
04044             if (!poped) {
04045                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04046             }
04047             ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
04048             ADD_LABEL(ret, lfin);
04049         }
04050         else {
04051             COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
04052             ADD_SEND(ret, line, ID2SYM(id), INT2FIX(1));
04053             if (!poped) {
04054                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04055             }
04056             if (flag & VM_CALL_ARGS_SPLAT) {
04057                 ADD_INSN1(ret, line, newarray, INT2FIX(1));
04058                 if (boff > 0) {
04059                     ADD_INSN1(ret, line, dupn, INT2FIX(3));
04060                     ADD_INSN(ret, line, swap);
04061                     ADD_INSN(ret, line, pop);
04062                 }
04063                 ADD_INSN(ret, line, concatarray);
04064                 if (boff > 0) {
04065                     ADD_INSN1(ret, line, setn, INT2FIX(3));
04066                     ADD_INSN(ret, line, pop);
04067                     ADD_INSN(ret, line, pop);
04068                 }
04069                 ADD_SEND_R(ret, line, ID2SYM(idASET),
04070                            argc, Qfalse, LONG2FIX(flag));
04071             }
04072             else {
04073                 if (boff > 0)
04074                     ADD_INSN(ret, line, swap);
04075                 ADD_SEND_R(ret, line, ID2SYM(idASET),
04076                            FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
04077             }
04078             ADD_INSN(ret, line, pop);
04079         }
04080 
04081         break;
04082       }
04083       case NODE_OP_ASGN2:{
04084         ID atype = node->nd_next->nd_mid;
04085         LABEL *lfin = NEW_LABEL(line);
04086         LABEL *lcfin = NEW_LABEL(line);
04087         /*
04088           class C; attr_accessor :c; end
04089           r = C.new
04090           r.a &&= v # asgn2
04091 
04092           eval r    # r
04093           dup       # r r
04094           eval r.a  # r o
04095 
04096           # or
04097           dup       # r o o
04098           if lcfin  # r o
04099           pop       # r
04100           eval v    # r v
04101           swap      # v r
04102           topn 1    # v r v
04103           send a=   # v ?
04104           jump lfin # v ?
04105 
04106           lcfin:      # r o
04107           swap      # o r
04108 
04109           lfin:       # o ?
04110           pop       # o
04111 
04112           # and
04113           dup       # r o o
04114           unless lcfin
04115           pop       # r
04116           eval v    # r v
04117           swap      # v r
04118           topn 1    # v r v
04119           send a=   # v ?
04120           jump lfin # v ?
04121 
04122           # others
04123           eval v    # r o v
04124           send ??   # r w
04125           send a=   # w
04126 
04127         */
04128 
04129         COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
04130         ADD_INSN(ret, line, dup);
04131         ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_vid),
04132                  INT2FIX(0));
04133 
04134         if (atype == 0 || atype == 1) { /* 0: OR or 1: AND */
04135             ADD_INSN(ret, line, dup);
04136             if (atype == 0) {
04137                 ADD_INSNL(ret, line, branchif, lcfin);
04138             }
04139             else {
04140                 ADD_INSNL(ret, line, branchunless, lcfin);
04141             }
04142             ADD_INSN(ret, line, pop);
04143             COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
04144             ADD_INSN(ret, line, swap);
04145             ADD_INSN1(ret, line, topn, INT2FIX(1));
04146             ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
04147                      INT2FIX(1));
04148             ADD_INSNL(ret, line, jump, lfin);
04149 
04150             ADD_LABEL(ret, lcfin);
04151             ADD_INSN(ret, line, swap);
04152 
04153             ADD_LABEL(ret, lfin);
04154             ADD_INSN(ret, line, pop);
04155             if (poped) {
04156                 /* we can apply more optimize */
04157                 ADD_INSN(ret, line, pop);
04158             }
04159         }
04160         else {
04161             COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
04162             ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_mid),
04163                      INT2FIX(1));
04164             if (!poped) {
04165                 ADD_INSN(ret, line, swap);
04166                 ADD_INSN1(ret, line, topn, INT2FIX(1));
04167             }
04168             ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
04169                      INT2FIX(1));
04170             ADD_INSN(ret, line, pop);
04171         }
04172         break;
04173       }
04174       case NODE_OP_CDECL: {
04175         LABEL *lfin = 0;
04176         LABEL *lassign = 0;
04177         ID mid;
04178 
04179         switch (nd_type(node->nd_head)) {
04180           case NODE_COLON3:
04181             ADD_INSN1(ret, line, putobject, rb_cObject);
04182             break;
04183           case NODE_COLON2:
04184             COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head);
04185             break;
04186           default:
04187             do {
04188                 COMPILE_ERROR((ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
04189                                ruby_node_name(nd_type(node->nd_head))));
04190             } while (0);
04191             return COMPILE_NG;
04192         }
04193         mid = node->nd_head->nd_mid;
04194         /* cref */
04195         if (node->nd_aid == 0) {
04196             lassign = NEW_LABEL(line);
04197             ADD_INSN(ret, line, dup); /* cref cref */
04198             ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
04199                       ID2SYM(mid), Qfalse); /* cref bool */
04200             ADD_INSNL(ret, line, branchunless, lassign); /* cref */
04201         }
04202         ADD_INSN(ret, line, dup); /* cref cref */
04203         ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
04204 
04205         if (node->nd_aid == 0 || node->nd_aid == 1) {
04206             lfin = NEW_LABEL(line);
04207             if (!poped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
04208             if (node->nd_aid == 0)
04209                 ADD_INSNL(ret, line, branchif, lfin);
04210             else
04211                 ADD_INSNL(ret, line, branchunless, lfin);
04212             /* cref [obj] */
04213             if (!poped) ADD_INSN(ret, line, pop); /* cref */
04214             if (lassign) ADD_LABEL(ret, lassign);
04215             COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
04216             /* cref value */
04217             if (poped)
04218                 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
04219             else {
04220                 ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
04221                 ADD_INSN(ret, line, swap); /* cref value value cref */
04222             }
04223             ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
04224             ADD_LABEL(ret, lfin);                           /* cref [value] */
04225             if (!poped) ADD_INSN(ret, line, swap); /* [value] cref */
04226             ADD_INSN(ret, line, pop); /* [value] */
04227         }
04228         else {
04229             COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
04230             /* cref obj value */
04231             ADD_CALL(ret, line, ID2SYM(node->nd_aid), INT2FIX(1));
04232             /* cref value */
04233             ADD_INSN(ret, line, swap); /* value cref */
04234             if (!poped) {
04235                 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
04236                 ADD_INSN(ret, line, swap); /* value value cref */
04237             }
04238             ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
04239         }
04240         break;
04241       }
04242       case NODE_OP_ASGN_AND:
04243       case NODE_OP_ASGN_OR:{
04244         LABEL *lfin = NEW_LABEL(line);
04245         LABEL *lassign;
04246 
04247         if (nd_type(node) == NODE_OP_ASGN_OR) {
04248             LABEL *lfinish[2];
04249             lfinish[0] = lfin;
04250             lfinish[1] = 0;
04251             defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
04252             lassign = lfinish[1];
04253             if (!lassign) {
04254                 lassign = NEW_LABEL(line);
04255             }
04256             ADD_INSNL(ret, line, branchunless, lassign);
04257         }
04258         else {
04259             lassign = NEW_LABEL(line);
04260         }
04261 
04262         COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
04263         ADD_INSN(ret, line, dup);
04264 
04265         if (nd_type(node) == NODE_OP_ASGN_AND) {
04266             ADD_INSNL(ret, line, branchunless, lfin);
04267         }
04268         else {
04269             ADD_INSNL(ret, line, branchif, lfin);
04270         }
04271 
04272         ADD_INSN(ret, line, pop);
04273         ADD_LABEL(ret, lassign);
04274         COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
04275         ADD_LABEL(ret, lfin);
04276 
04277         if (poped) {
04278             /* we can apply more optimize */
04279             ADD_INSN(ret, line, pop);
04280         }
04281         break;
04282       }
04283       case NODE_CALL:
04284       case NODE_FCALL:
04285       case NODE_VCALL:{         /* VCALL: variable or call */
04286         /*
04287           call:  obj.method(...)
04288           fcall: func(...)
04289           vcall: func
04290         */
04291         DECL_ANCHOR(recv);
04292         DECL_ANCHOR(args);
04293         ID mid = node->nd_mid;
04294         VALUE argc;
04295         VALUE flag = 0;
04296         VALUE parent_block = iseq->compile_data->current_block;
04297         iseq->compile_data->current_block = Qfalse;
04298 
04299         INIT_ANCHOR(recv);
04300         INIT_ANCHOR(args);
04301 #if SUPPORT_JOKE
04302         if (nd_type(node) == NODE_VCALL) {
04303             ID id_bitblt;
04304             ID id_answer;
04305 
04306             CONST_ID(id_bitblt, "bitblt");
04307             CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
04308 
04309             if (mid == id_bitblt) {
04310                 ADD_INSN(ret, line, bitblt);
04311                 break;
04312             }
04313             else if (mid == id_answer) {
04314                 ADD_INSN(ret, line, answer);
04315                 break;
04316             }
04317         }
04318         /* only joke */
04319         {
04320             ID goto_id;
04321             ID label_id;
04322 
04323             CONST_ID(goto_id, "__goto__");
04324             CONST_ID(label_id, "__label__");
04325 
04326             if (nd_type(node) == NODE_FCALL &&
04327                 (mid == goto_id || mid == label_id)) {
04328                 LABEL *label;
04329                 st_data_t data;
04330                 st_table *labels_table = iseq->compile_data->labels_table;
04331                 ID label_name;
04332 
04333                 if (!labels_table) {
04334                     labels_table = st_init_numtable();
04335                     iseq->compile_data->labels_table = labels_table;
04336                 }
04337                 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
04338                     SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
04339 
04340                     label_name = SYM2ID(node->nd_args->nd_head->nd_lit);
04341                     if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
04342                         label = NEW_LABEL(line);
04343                         label->position = line;
04344                         st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
04345                     }
04346                     else {
04347                         label = (LABEL *)data;
04348                     }
04349                 }
04350                 else {
04351                     COMPILE_ERROR((ERROR_ARGS "invalid goto/label format"));
04352                 }
04353 
04354 
04355                 if (mid == goto_id) {
04356                     ADD_INSNL(ret, line, jump, label);
04357                 }
04358                 else {
04359                     ADD_LABEL(ret, label);
04360                 }
04361                 break;
04362             }
04363         }
04364 #endif
04365         /* receiver */
04366         if (type == NODE_CALL) {
04367             COMPILE(recv, "recv", node->nd_recv);
04368         }
04369         else if (type == NODE_FCALL || type == NODE_VCALL) {
04370             ADD_CALL_RECEIVER(recv, line);
04371         }
04372 
04373         /* args */
04374         if (nd_type(node) != NODE_VCALL) {
04375             argc = setup_args(iseq, args, node->nd_args, &flag);
04376         }
04377         else {
04378             argc = INT2FIX(0);
04379         }
04380 
04381         ADD_SEQ(ret, recv);
04382         ADD_SEQ(ret, args);
04383 
04384         debugp_param("call args argc", argc);
04385         debugp_param("call method", ID2SYM(mid));
04386 
04387         switch (nd_type(node)) {
04388           case NODE_VCALL:
04389             flag |= VM_CALL_VCALL;
04390             /* VCALL is funcall, so fall through */
04391           case NODE_FCALL:
04392             flag |= VM_CALL_FCALL;
04393         }
04394 
04395         ADD_SEND_R(ret, line, ID2SYM(mid),
04396                    argc, parent_block, LONG2FIX(flag));
04397 
04398         if (poped) {
04399             ADD_INSN(ret, line, pop);
04400         }
04401         break;
04402       }
04403       case NODE_SUPER:
04404       case NODE_ZSUPER:{
04405         DECL_ANCHOR(args);
04406         int argc;
04407         VALUE flag = 0;
04408         VALUE parent_block = iseq->compile_data->current_block;
04409 
04410         INIT_ANCHOR(args);
04411         iseq->compile_data->current_block = Qfalse;
04412         if (nd_type(node) == NODE_SUPER) {
04413             VALUE vargc = setup_args(iseq, args, node->nd_args, &flag);
04414             argc = FIX2INT(vargc);
04415         }
04416         else {
04417             /* NODE_ZSUPER */
04418             int i;
04419             rb_iseq_t *liseq = iseq->local_iseq;
04420             int lvar_level = get_lvar_level(iseq);
04421 
04422             argc = liseq->argc;
04423 
04424             /* normal arguments */
04425             for (i = 0; i < liseq->argc; i++) {
04426                 int idx = liseq->local_size - i;
04427                 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04428             }
04429 
04430             if (!liseq->arg_simple) {
04431                 if (liseq->arg_opts) {
04432                     /* optional arguments */
04433                     int j;
04434                     for (j = 0; j < liseq->arg_opts - 1; j++) {
04435                         int idx = liseq->local_size - (i + j);
04436                         ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04437                     }
04438                     i += j;
04439                     argc = i;
04440                 }
04441 
04442                 if (liseq->arg_rest != -1) {
04443                     /* rest argument */
04444                     int idx = liseq->local_size - liseq->arg_rest;
04445                     ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04446                     argc = liseq->arg_rest + 1;
04447                     flag |= VM_CALL_ARGS_SPLAT;
04448                 }
04449 
04450                 if (liseq->arg_post_len) {
04451                     /* post arguments */
04452                     int post_len = liseq->arg_post_len;
04453                     int post_start = liseq->arg_post_start;
04454 
04455                     if (liseq->arg_rest != -1) {
04456                         int j;
04457                         for (j=0; j<post_len; j++) {
04458                             int idx = liseq->local_size - (post_start + j);
04459                             ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04460                         }
04461                         ADD_INSN1(args, line, newarray, INT2FIX(j));
04462                         ADD_INSN (args, line, concatarray);
04463                         /* argc is setteled at above */
04464                     }
04465                     else {
04466                         int j;
04467                         for (j=0; j<post_len; j++) {
04468                             int idx = liseq->local_size - (post_start + j);
04469                             ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04470                         }
04471                         argc = post_len + post_start;
04472                     }
04473                 }
04474 
04475                 if (liseq->arg_keyword >= 0) {
04476                     int local_size = liseq->local_size;
04477                     int idx = local_size - liseq->arg_keyword;
04478                     argc++;
04479                     ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04480                     ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04481                     ADD_SEND (args, line, ID2SYM(rb_intern("dup")), INT2FIX(0));
04482                     for (i = 0; i < liseq->arg_keywords; ++i) {
04483                         ID id = liseq->arg_keyword_table[i];
04484                         idx = local_size - get_local_var_idx(liseq, id);
04485                         ADD_INSN1(args, line, putobject, ID2SYM(id));
04486                         ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04487                     }
04488                     ADD_SEND(args, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i * 2 + 1));
04489                     if (liseq->arg_rest != -1) {
04490                         ADD_INSN1(args, line, newarray, INT2FIX(1));
04491                         ADD_INSN (args, line, concatarray);
04492                         --argc;
04493                     }
04494                 }
04495             }
04496         }
04497 
04498         /* dummy receiver */
04499         ADD_INSN1(ret, line, putobject, nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
04500         ADD_SEQ(ret, args);
04501         ADD_INSN1(ret, line, invokesuper, new_callinfo(iseq, 0, argc, parent_block,
04502                                                                 flag | VM_CALL_SUPER | VM_CALL_FCALL));
04503 
04504         if (poped) {
04505             ADD_INSN(ret, line, pop);
04506         }
04507         break;
04508       }
04509       case NODE_ARRAY:{
04510         compile_array_(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, poped);
04511         break;
04512       }
04513       case NODE_ZARRAY:{
04514         if (!poped) {
04515             ADD_INSN1(ret, line, newarray, INT2FIX(0));
04516         }
04517         break;
04518       }
04519       case NODE_VALUES:{
04520         NODE *n = node;
04521         while (n) {
04522             COMPILE(ret, "values item", n->nd_head);
04523             n = n->nd_next;
04524         }
04525         ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
04526         if (poped) {
04527             ADD_INSN(ret, line, pop);
04528         }
04529         break;
04530       }
04531       case NODE_HASH:{
04532         DECL_ANCHOR(list);
04533         int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
04534 
04535         INIT_ANCHOR(list);
04536         switch (type) {
04537           case NODE_ARRAY:
04538             compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH);
04539             ADD_SEQ(ret, list);
04540             break;
04541 
04542           case NODE_ZARRAY:
04543             ADD_INSN1(ret, line, newhash, INT2FIX(0));
04544             break;
04545 
04546           default:
04547             rb_bug("can't make hash with this node: %s", ruby_node_name(type));
04548         }
04549 
04550         if (poped) {
04551             ADD_INSN(ret, line, pop);
04552         }
04553         break;
04554       }
04555       case NODE_RETURN:{
04556         rb_iseq_t *is = iseq;
04557 
04558         if (is) {
04559             if (is->type == ISEQ_TYPE_TOP) {
04560                 COMPILE_ERROR((ERROR_ARGS "Invalid return"));
04561             }
04562             else {
04563                 LABEL *splabel = 0;
04564 
04565                 if (is->type == ISEQ_TYPE_METHOD) {
04566                     splabel = NEW_LABEL(0);
04567                     ADD_LABEL(ret, splabel);
04568                     ADD_ADJUST(ret, line, 0);
04569                 }
04570 
04571                 COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
04572 
04573                 if (is->type == ISEQ_TYPE_METHOD) {
04574                     add_ensure_iseq(ret, iseq, 1);
04575                     ADD_TRACE(ret, line, RUBY_EVENT_RETURN);
04576                     ADD_INSN(ret, line, leave);
04577                     ADD_ADJUST_RESTORE(ret, splabel);
04578 
04579                     if (!poped) {
04580                         ADD_INSN(ret, line, putnil);
04581                     }
04582                 }
04583                 else {
04584                     ADD_INSN1(ret, line, throw, INT2FIX(0x01) /* TAG_RETURN */ );
04585                     if (poped) {
04586                         ADD_INSN(ret, line, pop);
04587                     }
04588                 }
04589             }
04590         }
04591         break;
04592       }
04593       case NODE_YIELD:{
04594         DECL_ANCHOR(args);
04595         VALUE argc;
04596         VALUE flag = 0;
04597 
04598         INIT_ANCHOR(args);
04599         if (iseq->type == ISEQ_TYPE_TOP) {
04600             COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
04601         }
04602 
04603         if (node->nd_head) {
04604             argc = setup_args(iseq, args, node->nd_head, &flag);
04605         }
04606         else {
04607             argc = INT2FIX(0);
04608         }
04609 
04610         ADD_SEQ(ret, args);
04611         ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), 0, flag));
04612 
04613         if (poped) {
04614             ADD_INSN(ret, line, pop);
04615         }
04616         break;
04617       }
04618       case NODE_LVAR:{
04619         if (!poped) {
04620             ID id = node->nd_vid;
04621             int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
04622 
04623             debugs("id: %s idx: %d\n", rb_id2name(id), idx);
04624             ADD_INSN2(ret, line, getlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
04625         }
04626         break;
04627       }
04628       case NODE_DVAR:{
04629         int lv, idx, ls;
04630         debugi("nd_vid", node->nd_vid);
04631         if (!poped) {
04632             idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
04633             if (idx < 0) {
04634                 rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
04635             }
04636             ADD_INSN2(ret, line, getlocal, INT2FIX(ls - idx), INT2FIX(lv));
04637         }
04638         break;
04639       }
04640       case NODE_GVAR:{
04641         ADD_INSN1(ret, line, getglobal,
04642                   ((VALUE)node->nd_entry | 1));
04643         if (poped) {
04644             ADD_INSN(ret, line, pop);
04645         }
04646         break;
04647       }
04648       case NODE_IVAR:{
04649         debugi("nd_vid", node->nd_vid);
04650         if (!poped) {
04651             ADD_INSN2(ret, line, getinstancevariable,
04652                       ID2SYM(node->nd_vid), INT2FIX(iseq->ic_size++));
04653         }
04654         break;
04655       }
04656       case NODE_CONST:{
04657         debugi("nd_vid", node->nd_vid);
04658 
04659         if (iseq->compile_data->option->inline_const_cache) {
04660             LABEL *lend = NEW_LABEL(line);
04661             int ic_index = iseq->ic_size++;
04662 
04663             ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
04664             ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
04665             ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
04666             ADD_LABEL(ret, lend);
04667         }
04668         else {
04669             ADD_INSN(ret, line, putnil);
04670             ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
04671         }
04672 
04673         if (poped) {
04674             ADD_INSN(ret, line, pop);
04675         }
04676         break;
04677       }
04678       case NODE_CVAR:{
04679         if (!poped) {
04680             ADD_INSN1(ret, line, getclassvariable,
04681                       ID2SYM(node->nd_vid));
04682         }
04683         break;
04684       }
04685       case NODE_NTH_REF:{
04686         if (!poped) {
04687             ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~'  */,
04688                       INT2FIX(node->nd_nth << 1));
04689         }
04690         break;
04691       }
04692       case NODE_BACK_REF:{
04693         if (!poped) {
04694             ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
04695                       INT2FIX(0x01 | (node->nd_nth << 1)));
04696         }
04697         break;
04698       }
04699       case NODE_MATCH:
04700       case NODE_MATCH2:
04701       case NODE_MATCH3:{
04702         DECL_ANCHOR(recv);
04703         DECL_ANCHOR(val);
04704 
04705         INIT_ANCHOR(recv);
04706         INIT_ANCHOR(val);
04707         switch (nd_type(node)) {
04708           case NODE_MATCH:
04709             ADD_INSN1(recv, line, putobject, node->nd_lit);
04710             ADD_INSN2(val, line, getspecial, INT2FIX(0),
04711                       INT2FIX(0));
04712             break;
04713           case NODE_MATCH2:
04714             COMPILE(recv, "receiver", node->nd_recv);
04715             COMPILE(val, "value", node->nd_value);
04716             break;
04717           case NODE_MATCH3:
04718             COMPILE(recv, "receiver", node->nd_value);
04719             COMPILE(val, "value", node->nd_recv);
04720             break;
04721         }
04722 
04723         if (iseq->compile_data->option->specialized_instruction) {
04724             /* TODO: detect by node */
04725             if (recv->last == recv->anchor.next &&
04726                 INSN_OF(recv->last) == BIN(putobject) &&
04727                 nd_type(node) == NODE_MATCH2) {
04728                 ADD_SEQ(ret, val);
04729                 ADD_INSN1(ret, line, opt_regexpmatch1,
04730                           OPERAND_AT(recv->last, 0));
04731             }
04732             else {
04733                 ADD_SEQ(ret, recv);
04734                 ADD_SEQ(ret, val);
04735                 ADD_INSN(ret, line, opt_regexpmatch2);
04736             }
04737         }
04738         else {
04739             ADD_SEQ(ret, recv);
04740             ADD_SEQ(ret, val);
04741             ADD_SEND(ret, line, ID2SYM(idEqTilde), INT2FIX(1));
04742         }
04743 
04744         if (poped) {
04745             ADD_INSN(ret, line, pop);
04746         }
04747         break;
04748       }
04749       case NODE_LIT:{
04750         debugp_param("lit", node->nd_lit);
04751         if (!poped) {
04752             ADD_INSN1(ret, line, putobject, node->nd_lit);
04753         }
04754         break;
04755       }
04756       case NODE_STR:{
04757         debugp_param("nd_lit", node->nd_lit);
04758         if (!poped) {
04759             OBJ_FREEZE(node->nd_lit);
04760             ADD_INSN1(ret, line, putstring, node->nd_lit);
04761         }
04762         break;
04763       }
04764       case NODE_DSTR:{
04765         compile_dstr(iseq, ret, node);
04766 
04767         if (poped) {
04768             ADD_INSN(ret, line, pop);
04769         }
04770         break;
04771       }
04772       case NODE_XSTR:{
04773         OBJ_FREEZE(node->nd_lit);
04774         ADD_CALL_RECEIVER(ret, line);
04775         ADD_INSN1(ret, line, putobject, node->nd_lit);
04776         ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
04777 
04778         if (poped) {
04779             ADD_INSN(ret, line, pop);
04780         }
04781         break;
04782       }
04783       case NODE_DXSTR:{
04784         ADD_CALL_RECEIVER(ret, line);
04785         compile_dstr(iseq, ret, node);
04786         ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
04787 
04788         if (poped) {
04789             ADD_INSN(ret, line, pop);
04790         }
04791         break;
04792       }
04793       case NODE_EVSTR:{
04794         COMPILE(ret, "nd_body", node->nd_body);
04795 
04796         if (poped) {
04797             ADD_INSN(ret, line, pop);
04798         }
04799         else {
04800             ADD_INSN(ret, line, tostring);
04801         }
04802         break;
04803       }
04804       case NODE_DREGX:{
04805         compile_dregx(iseq, ret, node);
04806 
04807         if (poped) {
04808             ADD_INSN(ret, line, pop);
04809         }
04810         break;
04811       }
04812       case NODE_DREGX_ONCE:{
04813         /* TODO: once? */
04814         LABEL *lend = NEW_LABEL(line);
04815         int ic_index = iseq->ic_size++;
04816 
04817         ADD_INSN2(ret, line, onceinlinecache, lend, INT2FIX(ic_index));
04818         ADD_INSN(ret, line, pop);
04819 
04820         compile_dregx(iseq, ret, node);
04821 
04822         ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
04823         ADD_LABEL(ret, lend);
04824 
04825         if (poped) {
04826             ADD_INSN(ret, line, pop);
04827         }
04828         break;
04829       }
04830       case NODE_ARGSCAT:{
04831         if (poped) {
04832             COMPILE(ret, "argscat head", node->nd_head);
04833             ADD_INSN1(ret, line, splatarray, Qfalse);
04834             ADD_INSN(ret, line, pop);
04835             COMPILE(ret, "argscat body", node->nd_body);
04836             ADD_INSN1(ret, line, splatarray, Qfalse);
04837             ADD_INSN(ret, line, pop);
04838         }
04839         else {
04840             COMPILE(ret, "argscat head", node->nd_head);
04841             COMPILE(ret, "argscat body", node->nd_body);
04842             ADD_INSN(ret, line, concatarray);
04843         }
04844         break;
04845       }
04846       case NODE_ARGSPUSH:{
04847         if (poped) {
04848             COMPILE(ret, "arsgpush head", node->nd_head);
04849             ADD_INSN1(ret, line, splatarray, Qfalse);
04850             ADD_INSN(ret, line, pop);
04851             COMPILE_(ret, "argspush body", node->nd_body, poped);
04852         }
04853         else {
04854             COMPILE(ret, "arsgpush head", node->nd_head);
04855             COMPILE_(ret, "argspush body", node->nd_body, poped);
04856             ADD_INSN1(ret, line, newarray, INT2FIX(1));
04857             ADD_INSN(ret, line, concatarray);
04858         }
04859         break;
04860       }
04861       case NODE_SPLAT:{
04862         COMPILE(ret, "splat", node->nd_head);
04863         ADD_INSN1(ret, line, splatarray, Qtrue);
04864 
04865         if (poped) {
04866             ADD_INSN(ret, line, pop);
04867         }
04868         break;
04869       }
04870       case NODE_DEFN:{
04871         VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
04872                                     rb_str_dup(rb_id2str(node->nd_mid)),
04873                                     ISEQ_TYPE_METHOD, line);
04874 
04875         debugp_param("defn/iseq", iseqval);
04876 
04877         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04878         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
04879         ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
04880         ADD_INSN1(ret, line, putiseq, iseqval);
04881         ADD_SEND (ret, line, ID2SYM(id_core_define_method), INT2FIX(3));
04882 
04883         if (poped) {
04884             ADD_INSN(ret, line, pop);
04885         }
04886 
04887         debugp_param("defn", iseqval);
04888         break;
04889       }
04890       case NODE_DEFS:{
04891         VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
04892                                     rb_str_dup(rb_id2str(node->nd_mid)),
04893                                     ISEQ_TYPE_METHOD, line);
04894 
04895         debugp_param("defs/iseq", iseqval);
04896 
04897         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04898         COMPILE(ret, "defs: recv", node->nd_recv);
04899         ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
04900         ADD_INSN1(ret, line, putiseq, iseqval);
04901         ADD_SEND (ret, line, ID2SYM(id_core_define_singleton_method), INT2FIX(3));
04902 
04903         if (poped) {
04904             ADD_INSN(ret, line, pop);
04905         }
04906         break;
04907       }
04908       case NODE_ALIAS:{
04909         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04910         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
04911         COMPILE(ret, "alias arg1", node->u1.node);
04912         COMPILE(ret, "alias arg2", node->u2.node);
04913         ADD_SEND(ret, line, ID2SYM(id_core_set_method_alias), INT2FIX(3));
04914 
04915         if (poped) {
04916             ADD_INSN(ret, line, pop);
04917         }
04918         break;
04919       }
04920       case NODE_VALIAS:{
04921         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04922         ADD_INSN1(ret, line, putobject, ID2SYM(node->u1.id));
04923         ADD_INSN1(ret, line, putobject, ID2SYM(node->u2.id));
04924         ADD_SEND(ret, line, ID2SYM(id_core_set_variable_alias), INT2FIX(2));
04925 
04926         if (poped) {
04927             ADD_INSN(ret, line, pop);
04928         }
04929         break;
04930       }
04931       case NODE_UNDEF:{
04932         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04933         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
04934         COMPILE(ret, "undef arg", node->u2.node);
04935         ADD_SEND(ret, line, ID2SYM(id_core_undef_method), INT2FIX(2));
04936 
04937         if (poped) {
04938             ADD_INSN(ret, line, pop);
04939         }
04940         break;
04941       }
04942       case NODE_CLASS:{
04943         VALUE iseqval =
04944             NEW_CHILD_ISEQVAL(
04945                 node->nd_body,
04946                 rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
04947                 ISEQ_TYPE_CLASS, line);
04948         VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
04949         int flags = VM_DEFINECLASS_TYPE_CLASS;
04950         if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
04951         if (node->nd_super) flags |= VM_DEFINECLASS_FLAG_HAS_SUPERCLASS;
04952         COMPILE(ret, "super", node->nd_super);
04953         ADD_INSN3(ret, line, defineclass,
04954                   ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
04955 
04956         if (poped) {
04957             ADD_INSN(ret, line, pop);
04958         }
04959         break;
04960       }
04961       case NODE_MODULE:{
04962         VALUE iseqval = NEW_CHILD_ISEQVAL(
04963             node->nd_body,
04964             rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
04965             ISEQ_TYPE_CLASS, line);
04966 
04967         VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
04968         int flags = VM_DEFINECLASS_TYPE_MODULE;
04969         if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
04970         ADD_INSN (ret, line, putnil); /* dummy */
04971         ADD_INSN3(ret, line, defineclass,
04972                   ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
04973         if (poped) {
04974             ADD_INSN(ret, line, pop);
04975         }
04976         break;
04977       }
04978       case NODE_SCLASS:{
04979         ID singletonclass;
04980         VALUE iseqval =
04981             NEW_ISEQVAL(node->nd_body, rb_str_new2("singleton class"),
04982                         ISEQ_TYPE_CLASS, line);
04983 
04984         COMPILE(ret, "sclass#recv", node->nd_recv);
04985         ADD_INSN (ret, line, putnil);
04986         CONST_ID(singletonclass, "singletonclass");
04987         ADD_INSN3(ret, line, defineclass,
04988                   ID2SYM(singletonclass), iseqval,
04989                   INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
04990 
04991         if (poped) {
04992             ADD_INSN(ret, line, pop);
04993         }
04994         break;
04995       }
04996       case NODE_COLON2:{
04997         if (rb_is_const_id(node->nd_mid)) {
04998             /* constant */
04999             LABEL *lend = NEW_LABEL(line);
05000             int ic_index = iseq->ic_size++;
05001 
05002             DECL_ANCHOR(pref);
05003             DECL_ANCHOR(body);
05004 
05005             INIT_ANCHOR(pref);
05006             INIT_ANCHOR(body);
05007             compile_colon2(iseq, node, pref, body);
05008             if (LIST_SIZE_ZERO(pref)) {
05009                 if (iseq->compile_data->option->inline_const_cache) {
05010                     ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
05011                 }
05012                 else {
05013                     ADD_INSN(ret, line, putnil);
05014                 }
05015 
05016                 ADD_SEQ(ret, body);
05017 
05018                 if (iseq->compile_data->option->inline_const_cache) {
05019                     ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
05020                     ADD_LABEL(ret, lend);
05021                 }
05022             }
05023             else {
05024                 ADD_SEQ(ret, pref);
05025                 ADD_SEQ(ret, body);
05026             }
05027         }
05028         else {
05029             /* function call */
05030             ADD_CALL_RECEIVER(ret, line);
05031             COMPILE(ret, "colon2#nd_head", node->nd_head);
05032             ADD_CALL(ret, line, ID2SYM(node->nd_mid),
05033                      INT2FIX(1));
05034         }
05035         if (poped) {
05036             ADD_INSN(ret, line, pop);
05037         }
05038         break;
05039       }
05040       case NODE_COLON3:{
05041         LABEL *lend = NEW_LABEL(line);
05042         int ic_index = iseq->ic_size++;
05043 
05044         debugi("colon3#nd_mid", node->nd_mid);
05045 
05046         /* add cache insn */
05047         if (iseq->compile_data->option->inline_const_cache) {
05048             ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
05049             ADD_INSN(ret, line, pop);
05050         }
05051 
05052         ADD_INSN1(ret, line, putobject, rb_cObject);
05053         ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
05054 
05055         if (iseq->compile_data->option->inline_const_cache) {
05056             ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
05057             ADD_LABEL(ret, lend);
05058         }
05059 
05060         if (poped) {
05061             ADD_INSN(ret, line, pop);
05062         }
05063         break;
05064       }
05065       case NODE_DOT2:
05066       case NODE_DOT3:{
05067         VALUE flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
05068         COMPILE(ret, "min", (NODE *) node->nd_beg);
05069         COMPILE(ret, "max", (NODE *) node->nd_end);
05070         if (poped) {
05071             ADD_INSN(ret, line, pop);
05072             ADD_INSN(ret, line, pop);
05073         }
05074         else {
05075             ADD_INSN1(ret, line, newrange, flag);
05076         }
05077         break;
05078       }
05079       case NODE_FLIP2:
05080       case NODE_FLIP3:{
05081         LABEL *lend = NEW_LABEL(line);
05082         LABEL *lfin = NEW_LABEL(line);
05083         LABEL *ltrue = NEW_LABEL(line);
05084         rb_iseq_t *local_iseq = iseq->local_iseq;
05085         rb_num_t cnt;
05086         VALUE key;
05087 
05088         cnt = local_iseq->flip_cnt++ + DEFAULT_SPECIAL_VAR_COUNT;
05089         key = INT2FIX(cnt);
05090 
05091         ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
05092         ADD_INSNL(ret, line, branchif, lend);
05093 
05094         /* *flip == 0 */
05095         COMPILE(ret, "flip2 beg", node->nd_beg);
05096         ADD_INSN(ret, line, dup);
05097         ADD_INSNL(ret, line, branchunless, lfin);
05098         if (nd_type(node) == NODE_FLIP3) {
05099             ADD_INSN(ret, line, dup);
05100             ADD_INSN1(ret, line, setspecial, key);
05101             ADD_INSNL(ret, line, jump, lfin);
05102         }
05103         else {
05104             ADD_INSN1(ret, line, setspecial, key);
05105         }
05106 
05107         /* *flip == 1 */
05108         ADD_LABEL(ret, lend);
05109         COMPILE(ret, "flip2 end", node->nd_end);
05110         ADD_INSNL(ret, line, branchunless, ltrue);
05111         ADD_INSN1(ret, line, putobject, Qfalse);
05112         ADD_INSN1(ret, line, setspecial, key);
05113 
05114         ADD_LABEL(ret, ltrue);
05115         ADD_INSN1(ret, line, putobject, Qtrue);
05116 
05117         ADD_LABEL(ret, lfin);
05118         break;
05119       }
05120       case NODE_SELF:{
05121         if (!poped) {
05122             ADD_INSN(ret, line, putself);
05123         }
05124         break;
05125       }
05126       case NODE_NIL:{
05127         if (!poped) {
05128             ADD_INSN(ret, line, putnil);
05129         }
05130         break;
05131       }
05132       case NODE_TRUE:{
05133         if (!poped) {
05134             ADD_INSN1(ret, line, putobject, Qtrue);
05135         }
05136         break;
05137       }
05138       case NODE_FALSE:{
05139         if (!poped) {
05140             ADD_INSN1(ret, line, putobject, Qfalse);
05141         }
05142         break;
05143       }
05144       case NODE_ERRINFO:{
05145         if (!poped) {
05146             if (iseq->type == ISEQ_TYPE_RESCUE) {
05147                 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
05148             }
05149             else {
05150                 rb_iseq_t *ip = iseq;
05151                 int level = 0;
05152                 while (ip) {
05153                     if (ip->type == ISEQ_TYPE_RESCUE) {
05154                         break;
05155                     }
05156                     ip = ip->parent_iseq;
05157                     level++;
05158                 }
05159                 if (ip) {
05160                     ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(level));
05161                 }
05162                 else {
05163                     ADD_INSN(ret, line, putnil);
05164                 }
05165             }
05166         }
05167         break;
05168       }
05169       case NODE_DEFINED:{
05170         if (poped) break;
05171         if (!node->nd_head) {
05172             VALUE str = rb_iseq_defined_string(DEFINED_NIL);
05173             ADD_INSN1(ret, nd_line(node), putobject, str);
05174         }
05175         else {
05176             LABEL *lfinish[2];
05177             lfinish[0] = NEW_LABEL(line);
05178             lfinish[1] = 0;
05179             ADD_INSN(ret, line, putnil);
05180             defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
05181             ADD_INSN(ret, line, swap);
05182             ADD_INSN(ret, line, pop);
05183             if (lfinish[1]) {
05184                 ADD_LABEL(ret, lfinish[1]);
05185             }
05186             ADD_LABEL(ret, lfinish[0]);
05187         }
05188         break;
05189       }
05190       case NODE_POSTEXE:{
05191         LABEL *lend = NEW_LABEL(line);
05192         VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
05193         int ic_index = iseq->ic_size++;
05194 
05195         ADD_INSN2(ret, line, onceinlinecache, lend, INT2FIX(ic_index));
05196         ADD_INSN(ret, line, pop);
05197 
05198         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05199         ADD_INSN1(ret, line, putiseq, block);
05200         ADD_SEND (ret, line, ID2SYM(id_core_set_postexe), INT2FIX(1));
05201 
05202         ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
05203         ADD_LABEL(ret, lend);
05204 
05205         if (poped) {
05206             ADD_INSN(ret, line, pop);
05207         }
05208         break;
05209       }
05210       case NODE_KW_ARG:{
05211         LABEL *default_label = NEW_LABEL(line);
05212         LABEL *end_label = NEW_LABEL(line);
05213         int idx, lv, ls;
05214         ID id = node->nd_body->nd_vid;
05215 
05216         ADD_INSN(ret, line, dup);
05217         ADD_INSN1(ret, line, putobject, ID2SYM(id));
05218         ADD_SEND(ret, line, ID2SYM(rb_intern("key?")), INT2FIX(1));
05219         ADD_INSNL(ret, line, branchunless, default_label);
05220         ADD_INSN(ret, line, dup);
05221         ADD_INSN1(ret, line, putobject, ID2SYM(id));
05222         ADD_SEND(ret, line, ID2SYM(rb_intern("delete")), INT2FIX(1));
05223         switch (nd_type(node->nd_body)) {
05224           case NODE_LASGN:
05225             idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
05226             ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
05227             break;
05228           case NODE_DASGN:
05229           case NODE_DASGN_CURR:
05230             idx = get_dyna_var_idx(iseq, id, &lv, &ls);
05231             ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
05232             break;
05233           default:
05234             rb_bug("iseq_compile_each (NODE_KW_ARG): unknown node: %s", ruby_node_name(nd_type(node->nd_body)));
05235         }
05236         ADD_INSNL(ret, line, jump, end_label);
05237         ADD_LABEL(ret, default_label);
05238         COMPILE_POPED(ret, "keyword default argument", node->nd_body);
05239         ADD_LABEL(ret, end_label);
05240         break;
05241       }
05242       case NODE_DSYM:{
05243         compile_dstr(iseq, ret, node);
05244         if (!poped) {
05245             ADD_SEND(ret, line, ID2SYM(idIntern), INT2FIX(0));
05246         }
05247         else {
05248             ADD_INSN(ret, line, pop);
05249         }
05250         break;
05251       }
05252       case NODE_ATTRASGN:{
05253         DECL_ANCHOR(recv);
05254         DECL_ANCHOR(args);
05255         VALUE flag = 0;
05256         VALUE argc;
05257 
05258         INIT_ANCHOR(recv);
05259         INIT_ANCHOR(args);
05260         argc = setup_args(iseq, args, node->nd_args, &flag);
05261 
05262         if (node->nd_recv == (NODE *) 1) {
05263             flag |= VM_CALL_FCALL;
05264             ADD_INSN(recv, line, putself);
05265         }
05266         else {
05267             COMPILE(recv, "recv", node->nd_recv);
05268         }
05269 
05270         debugp_param("argc", argc);
05271         debugp_param("nd_mid", ID2SYM(node->nd_mid));
05272 
05273         if (!poped) {
05274             ADD_INSN(ret, line, putnil);
05275             ADD_SEQ(ret, recv);
05276             ADD_SEQ(ret, args);
05277 
05278             if (flag & VM_CALL_ARGS_BLOCKARG) {
05279                 ADD_INSN1(ret, line, topn, INT2FIX(1));
05280                 if (flag & VM_CALL_ARGS_SPLAT) {
05281                     ADD_INSN1(ret, line, putobject, INT2FIX(-1));
05282                     ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
05283                 }
05284                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
05285                 ADD_INSN (ret, line, pop);
05286             }
05287             else if (flag & VM_CALL_ARGS_SPLAT) {
05288                 ADD_INSN(ret, line, dup);
05289                 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
05290                 ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
05291                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
05292                 ADD_INSN (ret, line, pop);
05293             }
05294             else {
05295                 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
05296             }
05297         }
05298         else {
05299             ADD_SEQ(ret, recv);
05300             ADD_SEQ(ret, args);
05301         }
05302         ADD_SEND_R(ret, line, ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
05303         ADD_INSN(ret, line, pop);
05304 
05305         break;
05306       }
05307       case NODE_PRELUDE:{
05308         COMPILE_POPED(ret, "prelude", node->nd_head);
05309         COMPILE_(ret, "body", node->nd_body, poped);
05310         break;
05311       }
05312       case NODE_LAMBDA:{
05313         /* compile same as lambda{...} */
05314         VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
05315         VALUE argc = INT2FIX(0);
05316         ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05317         ADD_CALL_WITH_BLOCK(ret, line, ID2SYM(idLambda), argc, block);
05318 
05319         if (poped) {
05320             ADD_INSN(ret, line, pop);
05321         }
05322         break;
05323       }
05324       default:
05325         rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
05326         return COMPILE_NG;
05327     }
05328 
05329     debug_node_end();
05330     return COMPILE_OK;
05331 }
05332 
05333 /***************************/
05334 /* instruction information */
05335 /***************************/
05336 
05337 static int
05338 insn_data_length(INSN *iobj)
05339 {
05340     return insn_len(iobj->insn_id);
05341 }
05342 
05343 static int
05344 calc_sp_depth(int depth, INSN *insn)
05345 {
05346     return insn_stack_increase(depth, insn->insn_id, insn->operands);
05347 }
05348 
05349 static int
05350 insn_data_line_no(INSN *iobj)
05351 {
05352     return insn_len(iobj->line_no);
05353 }
05354 
05355 static VALUE
05356 insn_data_to_s_detail(INSN *iobj)
05357 {
05358     VALUE str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
05359 
05360     if (iobj->operands) {
05361         const char *types = insn_op_types(iobj->insn_id);
05362         int j;
05363 
05364         for (j = 0; types[j]; j++) {
05365             char type = types[j];
05366             printf("str: %"PRIxVALUE", type: %c\n", str, type);
05367 
05368             switch (type) {
05369               case TS_OFFSET:   /* label(destination position) */
05370                 {
05371                     LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
05372                     rb_str_catf(str, "<L%03d>", lobj->label_no);
05373                     break;
05374                 }
05375                 break;
05376               case TS_ISEQ:     /* iseq */
05377                 {
05378                     rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
05379                     VALUE val = Qnil;
05380                     if (0 && iseq) { /* TODO: invalidate now */
05381                         val = iseq->self;
05382                     }
05383                     rb_str_concat(str, rb_inspect(val));
05384                 }
05385                 break;
05386               case TS_LINDEX:
05387               case TS_NUM:      /* ulong */
05388               case TS_VALUE:    /* VALUE */
05389                 {
05390                     VALUE v = OPERAND_AT(iobj, j);
05391                     rb_str_concat(str, rb_inspect(v));
05392                     break;
05393                 }
05394               case TS_ID:       /* ID */
05395                 rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j)));
05396                 break;
05397               case TS_GENTRY:
05398                 {
05399                     struct rb_global_entry *entry = (struct rb_global_entry *)
05400                       (OPERAND_AT(iobj, j) & (~1));
05401                     rb_str_cat2(str, rb_id2name(entry->id));
05402                     break;
05403                 }
05404               case TS_IC:       /* inline cache */
05405                 rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
05406                 break;
05407               case TS_CALLINFO: /* call info */
05408                 {
05409                     rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, j);
05410                     rb_str_catf(str, "<callinfo:%s, %d>", ci->mid ? rb_id2name(ci->mid) : "", ci->orig_argc);
05411                     break;
05412                 }
05413               case TS_CDHASH:   /* case/when condition cache */
05414                 rb_str_cat2(str, "<ch>");
05415                 break;
05416               default:{
05417                 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
05418               }
05419             }
05420             if (types[j + 1]) {
05421                 rb_str_cat2(str, ", ");
05422             }
05423         }
05424     }
05425     return str;
05426 }
05427 
05428 static void
05429 dump_disasm_list(struct iseq_link_element *link)
05430 {
05431     int pos = 0;
05432     INSN *iobj;
05433     LABEL *lobj;
05434     VALUE str;
05435 
05436     printf("-- raw disasm--------\n");
05437 
05438     while (link) {
05439         switch (link->type) {
05440           case ISEQ_ELEMENT_INSN:
05441             {
05442                 iobj = (INSN *)link;
05443                 str = insn_data_to_s_detail(iobj);
05444                 printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str), insn_data_line_no(iobj));
05445                 pos += insn_data_length(iobj);
05446                 break;
05447             }
05448           case ISEQ_ELEMENT_LABEL:
05449             {
05450                 lobj = (LABEL *)link;
05451                 printf("<L%03d>\n", lobj->label_no);
05452                 break;
05453             }
05454           case ISEQ_ELEMENT_NONE:
05455             {
05456                 printf("[none]\n");
05457                 break;
05458             }
05459           case ISEQ_ELEMENT_ADJUST:
05460             {
05461                 ADJUST *adjust = (ADJUST *)link;
05462                 printf("adjust: [label: %d]\n", adjust->label->label_no);
05463                 break;
05464             }
05465           default:
05466             /* ignore */
05467             rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
05468         }
05469         link = link->next;
05470     }
05471     printf("---------------------\n");
05472 }
05473 
05474 const char *
05475 rb_insns_name(int i)
05476 {
05477     return insn_name_info[i];
05478 }
05479 
05480 VALUE
05481 rb_insns_name_array(void)
05482 {
05483     VALUE ary = rb_ary_new();
05484     int i;
05485     for (i = 0; i < numberof(insn_name_info); i++) {
05486         rb_ary_push(ary, rb_obj_freeze(rb_str_new2(insn_name_info[i])));
05487     }
05488     return rb_obj_freeze(ary);
05489 }
05490 
05491 static LABEL *
05492 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
05493 {
05494     LABEL *label = 0;
05495     st_data_t tmp;
05496     obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
05497 
05498     if (st_lookup(labels_table, obj, &tmp) == 0) {
05499         label = NEW_LABEL(0);
05500         st_insert(labels_table, obj, (st_data_t)label);
05501     }
05502     else {
05503         label = (LABEL *)tmp;
05504     }
05505     return label;
05506 }
05507 
05508 static VALUE
05509 get_exception_sym2type(VALUE sym)
05510 {
05511 #undef rb_intern
05512 #define rb_intern(str) rb_intern_const(str)
05513     VALUE sym_inspect;
05514     static VALUE symRescue, symEnsure, symRetry;
05515     static VALUE symBreak, symRedo, symNext;
05516 
05517     if (symRescue == 0) {
05518         symRescue = ID2SYM(rb_intern("rescue"));
05519         symEnsure = ID2SYM(rb_intern("ensure"));
05520         symRetry  = ID2SYM(rb_intern("retry"));
05521         symBreak  = ID2SYM(rb_intern("break"));
05522         symRedo   = ID2SYM(rb_intern("redo"));
05523         symNext   = ID2SYM(rb_intern("next"));
05524     }
05525 
05526     if (sym == symRescue) return CATCH_TYPE_RESCUE;
05527     if (sym == symEnsure) return CATCH_TYPE_ENSURE;
05528     if (sym == symRetry)  return CATCH_TYPE_RETRY;
05529     if (sym == symBreak)  return CATCH_TYPE_BREAK;
05530     if (sym == symRedo)   return CATCH_TYPE_REDO;
05531     if (sym == symNext)   return CATCH_TYPE_NEXT;
05532     sym_inspect = rb_inspect(sym);
05533     rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
05534              StringValuePtr(sym_inspect));
05535     return 0;
05536 }
05537 
05538 static int
05539 iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
05540                      VALUE exception)
05541 {
05542     int i;
05543 
05544     for (i=0; i<RARRAY_LEN(exception); i++) {
05545         VALUE v, type, *ptr, eiseqval;
05546         LABEL *lstart, *lend, *lcont;
05547         int sp;
05548 
05549         RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
05550                                          "Array", "to_ary");
05551         if (RARRAY_LEN(v) != 6) {
05552             rb_raise(rb_eSyntaxError, "wrong exception entry");
05553         }
05554         ptr  = RARRAY_PTR(v);
05555         type = get_exception_sym2type(ptr[0]);
05556         if (ptr[1] == Qnil) {
05557             eiseqval = 0;
05558         }
05559         else {
05560             eiseqval = rb_iseq_load(ptr[1], iseq->self, Qnil);
05561         }
05562 
05563         lstart = register_label(iseq, labels_table, ptr[2]);
05564         lend   = register_label(iseq, labels_table, ptr[3]);
05565         lcont  = register_label(iseq, labels_table, ptr[4]);
05566         sp     = NUM2INT(ptr[5]);
05567 
05568         (void)sp;
05569 
05570         ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
05571     }
05572     return COMPILE_OK;
05573 }
05574 
05575 static struct st_table *
05576 insn_make_insn_table(void)
05577 {
05578     struct st_table *table;
05579     int i;
05580     table = st_init_numtable();
05581 
05582     for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
05583         st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
05584     }
05585 
05586     return table;
05587 }
05588 
05589 static VALUE
05590 iseq_build_load_iseq(rb_iseq_t *iseq, VALUE op)
05591 {
05592     VALUE iseqval;
05593     if (RB_TYPE_P(op, T_ARRAY)) {
05594         iseqval = rb_iseq_load(op, iseq->self, Qnil);
05595     }
05596     else if (CLASS_OF(op) == rb_cISeq) {
05597         iseqval = op;
05598     }
05599     else {
05600         rb_raise(rb_eSyntaxError, "ISEQ is required");
05601     }
05602     iseq_add_mark_object(iseq, iseqval);
05603     return iseqval;
05604 }
05605 
05606 static int
05607 iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
05608                 VALUE body, struct st_table *labels_table)
05609 {
05610     /* TODO: body should be frozen */
05611     VALUE *ptr = RARRAY_PTR(body);
05612     long i, len = RARRAY_LEN(body);
05613     int j;
05614     int line_no = 0;
05615 
05616     /*
05617      * index -> LABEL *label
05618      */
05619     static struct st_table *insn_table;
05620 
05621     if (insn_table == 0) {
05622         insn_table = insn_make_insn_table();
05623     }
05624 
05625     for (i=0; i<len; i++) {
05626         VALUE obj = ptr[i];
05627 
05628         if (SYMBOL_P(obj)) {
05629             LABEL *label = register_label(iseq, labels_table, obj);
05630             ADD_LABEL(anchor, label);
05631         }
05632         else if (FIXNUM_P(obj)) {
05633             line_no = NUM2INT(obj);
05634         }
05635         else if (RB_TYPE_P(obj, T_ARRAY)) {
05636             VALUE *argv = 0;
05637             int argc = RARRAY_LENINT(obj) - 1;
05638             st_data_t insn_id;
05639             VALUE insn;
05640 
05641             insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
05642             if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
05643                 /* TODO: exception */
05644                 RB_GC_GUARD(insn) = rb_inspect(insn);
05645                 rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
05646                                  "unknown instruction: %s", RSTRING_PTR(insn));
05647             }
05648 
05649             if (argc != insn_len((VALUE)insn_id)-1) {
05650                 rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
05651                                  "operand size mismatch");
05652             }
05653 
05654             if (argc > 0) {
05655                 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
05656                 for (j=0; j<argc; j++) {
05657                     VALUE op = rb_ary_entry(obj, j+1);
05658                     switch (insn_op_type((VALUE)insn_id, j)) {
05659                       case TS_OFFSET: {
05660                         LABEL *label = register_label(iseq, labels_table, op);
05661                         argv[j] = (VALUE)label;
05662                         break;
05663                       }
05664                       case TS_LINDEX:
05665                       case TS_NUM:
05666                         (void)NUM2INT(op);
05667                         argv[j] = op;
05668                         break;
05669                       case TS_VALUE:
05670                         argv[j] = op;
05671                         iseq_add_mark_object(iseq, op);
05672                         break;
05673                       case TS_ISEQ:
05674                         {
05675                             if (op != Qnil) {
05676                                 argv[j] = iseq_build_load_iseq(iseq, op);
05677                             }
05678                             else {
05679                                 argv[j] = 0;
05680                             }
05681                         }
05682                         break;
05683                       case TS_GENTRY:
05684                         op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
05685                         argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
05686                         break;
05687                       case TS_IC:
05688                         argv[j] = op;
05689                         if (NUM2INT(op) >= iseq->ic_size) {
05690                             iseq->ic_size = NUM2INT(op) + 1;
05691                         }
05692                         break;
05693                       case TS_CALLINFO:
05694                         {
05695                             ID mid = 0;
05696                             int orig_argc = 0;
05697                             VALUE block = 0;
05698                             unsigned long flag = 0;
05699 
05700                             if (!NIL_P(op)) {
05701                                 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
05702                                 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
05703                                 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
05704                                 VALUE vblock = rb_hash_aref(op, ID2SYM(rb_intern("block")));
05705 
05706                                 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
05707                                 if (!NIL_P(vflag)) flag = NUM2ULONG(vflag);
05708                                 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
05709                                 if (!NIL_P(vblock)) block = iseq_build_load_iseq(iseq, vblock);
05710                             }
05711                             argv[j] = (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag);
05712                         }
05713                         break;
05714                       case TS_ID:
05715                         argv[j] = rb_convert_type(op, T_SYMBOL,
05716                                                   "Symbol", "to_sym");
05717                         break;
05718                       case TS_CDHASH:
05719                         {
05720                             int i;
05721                             op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
05722                             op = rb_ary_dup(op);
05723                             for (i=0; i<RARRAY_LEN(op); i+=2) {
05724                                 VALUE sym = rb_ary_entry(op, i+1);
05725                                 LABEL *label =
05726                                   register_label(iseq, labels_table, sym);
05727                                 rb_ary_store(op, i+1, (VALUE)label | 1);
05728                             }
05729                             argv[j] = op;
05730                             iseq_add_mark_object_compile_time(iseq, op);
05731                         }
05732                         break;
05733                       default:
05734                         rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
05735                     }
05736                 }
05737             }
05738             ADD_ELEM(anchor,
05739                      (LINK_ELEMENT*)new_insn_core(iseq, line_no,
05740                                                   (enum ruby_vminsn_type)insn_id, argc, argv));
05741         }
05742         else {
05743             rb_raise(rb_eTypeError, "unexpected object for instruction");
05744         }
05745     }
05746     validate_labels(iseq, labels_table);
05747     st_free_table(labels_table);
05748     iseq_setup(iseq, anchor);
05749     return COMPILE_OK;
05750 }
05751 
05752 #define CHECK_ARRAY(v)   rb_convert_type((v), T_ARRAY, "Array", "to_ary")
05753 #define CHECK_STRING(v)  rb_convert_type((v), T_STRING, "String", "to_str")
05754 #define CHECK_SYMBOL(v)  rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
05755 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
05756 
05757 VALUE
05758 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
05759                          VALUE exception, VALUE body)
05760 {
05761     int i;
05762     ID *tbl;
05763     struct st_table *labels_table = st_init_numtable();
05764     DECL_ANCHOR(anchor);
05765     INIT_ANCHOR(anchor);
05766 
05767     iseq->local_table_size = RARRAY_LENINT(locals);
05768     iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
05769     iseq->local_size = iseq->local_table_size + 1;
05770 
05771     for (i=0; i<RARRAY_LEN(locals); i++) {
05772         VALUE lv = RARRAY_PTR(locals)[i];
05773         tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
05774     }
05775 
05776     /* args */
05777     if (FIXNUM_P(args)) {
05778         iseq->arg_size = iseq->argc = FIX2INT(args);
05779         iseq->arg_simple = 1;
05780     }
05781     else {
05782         int i = 0;
05783         VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
05784         VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
05785         VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
05786         VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
05787         VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
05788         VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
05789         VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
05790 
05791         iseq->argc = FIX2INT(argc);
05792         iseq->arg_rest = FIX2INT(arg_rest);
05793         iseq->arg_post_len = FIX2INT(arg_post_len);
05794         iseq->arg_post_start = FIX2INT(arg_post_start);
05795         iseq->arg_block = FIX2INT(arg_block);
05796         iseq->arg_opts = RARRAY_LENINT(arg_opt_labels);
05797         iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
05798 
05799         if (iseq->arg_block != -1) {
05800             iseq->arg_size = iseq->arg_block + 1;
05801         }
05802         else if (iseq->arg_post_len) {
05803             iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
05804         }
05805         else if (iseq->arg_rest != -1) {
05806             iseq->arg_size = iseq->arg_rest + 1;
05807         }
05808         else {
05809             iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
05810         }
05811 
05812         for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
05813             iseq->arg_opt_table[i] =
05814               (VALUE)register_label(iseq, labels_table,
05815                                     rb_ary_entry(arg_opt_labels, i));
05816         }
05817 
05818         iseq->arg_simple = NUM2INT(arg_simple);
05819     }
05820 
05821     /* exception */
05822     iseq_build_from_ary_exception(iseq, labels_table, exception);
05823 
05824     /* body */
05825     iseq_build_from_ary_body(iseq, anchor, body, labels_table);
05826     return iseq->self;
05827 }
05828 
05829 /* for parser */
05830 
05831 int
05832 rb_dvar_defined(ID id)
05833 {
05834     rb_thread_t *th = GET_THREAD();
05835     rb_iseq_t *iseq;
05836     if (th->base_block && (iseq = th->base_block->iseq)) {
05837         while (iseq->type == ISEQ_TYPE_BLOCK ||
05838                iseq->type == ISEQ_TYPE_RESCUE ||
05839                iseq->type == ISEQ_TYPE_ENSURE ||
05840                iseq->type == ISEQ_TYPE_EVAL ||
05841                iseq->type == ISEQ_TYPE_MAIN
05842                ) {
05843             int i;
05844 
05845             for (i = 0; i < iseq->local_table_size; i++) {
05846                 if (iseq->local_table[i] == id) {
05847                     return 1;
05848                 }
05849             }
05850             iseq = iseq->parent_iseq;
05851         }
05852     }
05853     return 0;
05854 }
05855 
05856 int
05857 rb_local_defined(ID id)
05858 {
05859     rb_thread_t *th = GET_THREAD();
05860     rb_iseq_t *iseq;
05861 
05862     if (th->base_block && th->base_block->iseq) {
05863         int i;
05864         iseq = th->base_block->iseq->local_iseq;
05865 
05866         for (i=0; i<iseq->local_table_size; i++) {
05867             if (iseq->local_table[i] == id) {
05868                 return 1;
05869             }
05870         }
05871     }
05872     return 0;
05873 }
05874 
05875 int
05876 rb_parse_in_eval(void)
05877 {
05878     return GET_THREAD()->parse_in_eval > 0;
05879 }
05880 
05881 int
05882 rb_parse_in_main(void)
05883 {
05884     return GET_THREAD()->parse_in_eval < 0;
05885 }
05886