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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7