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