• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

compile.c

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

Generated on Thu Sep 8 2011 03:46:41 for Ruby by  doxygen 1.7.1