Ruby 1.9.2p136(2010-12-25revision30365)

- 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     static VALUE symRescue, symEnsure, symRetry;
    05156     static VALUE symBreak, symRedo, symNext;
    05157
    05158     if (symRescue == 0) {
    05159         symRescue = ID2SYM(rb_intern("rescue"));
    05160         symEnsure = ID2SYM(rb_intern("ensure"));
    05161         symRetry  = ID2SYM(rb_intern("retry"));
    05162         symBreak  = ID2SYM(rb_intern("break"));
    05163         symRedo   = ID2SYM(rb_intern("redo"));
    05164         symNext   = ID2SYM(rb_intern("next"));
    05165     }
    05166
    05167     if (sym == symRescue) return CATCH_TYPE_RESCUE;
    05168     if (sym == symEnsure) return CATCH_TYPE_ENSURE;
    05169     if (sym == symRetry)  return CATCH_TYPE_RETRY;
    05170     if (sym == symBreak)  return CATCH_TYPE_BREAK;
    05171     if (sym == symRedo)   return  CATCH_TYPE_REDO;
    05172     if (sym == symNext)   return CATCH_TYPE_NEXT;
    05173     rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
    05174              RSTRING_PTR(rb_inspect(sym)));
    05175     return 0;
    05176 }
    05177
    05178 static int
    05179 iseq_build_exception(rb_iseq_t *iseq, struct st_table *labels_table,
    05180                      VALUE exception)
    05181 {
    05182     int i;
    05183
    05184     for (i=0; i<RARRAY_LEN(exception); i++) {
    05185         VALUE v, type, *ptr, eiseqval;
    05186         LABEL *lstart, *lend, *lcont;
    05187         int sp;
    05188
    05189         RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
    05190                                          "Array", "to_ary");
    05191         if (RARRAY_LEN(v) != 6) {
    05192             rb_raise(rb_eSyntaxError, "wrong exception entry");
    05193         }
    05194         ptr  = RARRAY_PTR(v);
    05195         type = get_exception_sym2type(ptr[0]);
    05196         if (ptr[1] == Qnil) {
    05197             eiseqval = 0;
    05198         }
    05199         else {
    05200             eiseqval = rb_iseq_load(ptr[1], iseq->self, Qnil);
    05201         }
    05202
    05203         lstart = register_label(iseq, labels_table, ptr[2]);
    05204         lend   = register_label(iseq, labels_table, ptr[3]);
    05205         lcont  = register_label(iseq, labels_table, ptr[4]);
    05206         sp     = NUM2INT(ptr[5]);
    05207
    05208         ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
    05209     }
    05210     return COMPILE_OK;
    05211 }
    05212
    05213 static struct st_table *
    05214 insn_make_insn_table(void)
    05215 {
    05216     struct st_table *table;
    05217     int i;
    05218     table = st_init_numtable();
    05219
    05220     for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
    05221         st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
    05222     }
    05223
    05224     return table;
    05225 }
    05226
    05227 static int
    05228 iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
    05229                 VALUE body, struct st_table *labels_table)
    05230 {
    05231     /* TODO: body should be frozen */
    05232     VALUE *ptr = RARRAY_PTR(body);
    05233     long i, len = RARRAY_LEN(body);
    05234     int j;
    05235     int line_no = 0;
    05236     /*
    05237      * index -> LABEL *label
    05238      */
    05239     static struct st_table *insn_table;
    05240
    05241     if (insn_table == 0) {
    05242         insn_table = insn_make_insn_table();
    05243     }
    05244
    05245     for (i=0; i<len; i++) {
    05246         VALUE obj = ptr[i];
    05247
    05248         if (SYMBOL_P(obj)) {
    05249             LABEL *label = register_label(iseq, labels_table, obj);
    05250             ADD_LABEL(anchor, label);
    05251         }
    05252         else if (FIXNUM_P(obj)) {
    05253             line_no = NUM2INT(obj);
    05254         }
    05255         else if (TYPE(obj) == T_ARRAY) {
    05256             VALUE *argv = 0;
    05257             int argc = RARRAY_LENINT(obj) - 1;
    05258             VALUE insn_id;
    05259             VALUE insn;
    05260
    05261             insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
    05262             if (st_lookup(insn_table, insn, &insn_id) == 0) {
    05263                 /* TODO: exception */
    05264                 RB_GC_GUARD(insn) = rb_inspect(insn);
    05265                 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
    05266                                  "unknown instruction: %s", RSTRING_PTR(insn));
    05267             }
    05268
    05269             if (argc != insn_len(insn_id)-1) {
    05270                 rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
    05271                                  "operand size mismatch");
    05272             }
    05273
    05274             if (argc > 0) {
    05275                 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
    05276                 for (j=0; j<argc; j++) {
    05277                     VALUE op = rb_ary_entry(obj, j+1);
    05278                     switch (insn_op_type(insn_id, j)) {
    05279                       case TS_OFFSET: {
    05280                         LABEL *label = register_label(iseq, labels_table, op);
    05281                         argv[j] = (VALUE)label;
    05282                         break;
    05283                       }
    05284                       case TS_LINDEX:
    05285                       case TS_DINDEX:
    05286                       case TS_NUM:
    05287                         (void)NUM2INT(op);
    05288                         argv[j] = op;
    05289                         break;
    05290                       case TS_VALUE:
    05291                         argv[j] = op;
    05292                         iseq_add_mark_object(iseq, op);
    05293                         break;
    05294                       case TS_ISEQ:
    05295                         {
    05296                             if (op != Qnil) {
    05297                                 if (TYPE(op) == T_ARRAY) {
    05298                                     argv[j] = rb_iseq_load(op, iseq->self, Qnil);
    05299                                 }
    05300                                 else if (CLASS_OF(op) == rb_cISeq) {
    05301                                     argv[j] = op;
    05302                                 }
    05303                                 else {
    05304                                     rb_raise(rb_eSyntaxError, "ISEQ is required");
    05305                                 }
    05306                                 iseq_add_mark_object(iseq, argv[j]);
    05307                             }
    05308                             else {
    05309                                 argv[j] = 0;
    05310                             }
    05311                         }
    05312                         break;
    05313                       case TS_GENTRY:
    05314                         op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
    05315                         argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
    05316                         break;
    05317                       case TS_IC:
    05318                         argv[j] = op;
    05319                         if (NUM2INT(op) >= iseq->ic_size)
    05320                             iseq->ic_size = NUM2INT(op) + 1;
    05321                         break;
    05322                       case TS_ID:
    05323                         argv[j] = rb_convert_type(op, T_SYMBOL,
    05324                                                   "Symbol", "to_sym");
    05325                         break;
    05326                       case TS_CDHASH:
    05327                         {
    05328                             int i;
    05329                             op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
    05330                             op = rb_ary_dup(op);
    05331                             for (i=0; i<RARRAY_LEN(op); i+=2) {
    05332                                 VALUE sym = rb_ary_entry(op, i+1);
    05333                                 LABEL *label =
    05334                                   register_label(iseq, labels_table, sym);
    05335                                 rb_ary_store(op, i+1, (VALUE)label | 1);
    05336                             }
    05337                             argv[j] = op;
    05338                             iseq_add_mark_object_compile_time(iseq, op);
    05339                         }
    05340                         break;
    05341                       default:
    05342                         rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type(insn_id, j));
    05343                     }
    05344                 }
    05345             }
    05346             ADD_ELEM(anchor,
    05347                      (LINK_ELEMENT*)new_insn_core(iseq, line_no,
    05348                                                   (enum ruby_vminsn_type)insn_id, argc, argv));
    05349         }
    05350         else {
    05351             rb_raise(rb_eTypeError, "unexpected object for instruction");
    05352         }
    05353     }
    05354     st_free_table(labels_table);
    05355     iseq_setup(iseq, anchor);
    05356     return COMPILE_OK;
    05357 }
    05358
    05359 #define CHECK_ARRAY(v)   rb_convert_type(v, T_ARRAY, "Array", "to_ary")
    05360 #define CHECK_STRING(v)  rb_convert_type(v, T_STRING, "String", "to_str")
    05361 #define CHECK_SYMBOL(v)  rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
    05362 static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;}
    05363
    05364 VALUE
    05365 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
    05366                          VALUE exception, VALUE body)
    05367 {
    05368     int i;
    05369     ID *tbl;
    05370     struct st_table *labels_table = st_init_numtable();
    05371
    05372     DECL_ANCHOR(anchor);
    05373
    05374     INIT_ANCHOR(anchor);
    05375
    05376     iseq->local_table_size = RARRAY_LENINT(locals);
    05377     iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
    05378     iseq->local_size = iseq->local_table_size + 1;
    05379
    05380     for (i=0; i<RARRAY_LEN(locals); i++) {
    05381         VALUE lv = RARRAY_PTR(locals)[i];
    05382         tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
    05383     }
    05384
    05385     /* args */
    05386     if (FIXNUM_P(args)) {
    05387         iseq->arg_size = iseq->argc = FIX2INT(args);
    05388         iseq->arg_simple = 1;
    05389     }
    05390     else {
    05391         int i = 0;
    05392         VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
    05393         VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
    05394         VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
    05395         VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
    05396         VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
    05397         VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
    05398         VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
    05399
    05400         iseq->argc = FIX2INT(argc);
    05401         iseq->arg_rest = FIX2INT(arg_rest);
    05402         iseq->arg_post_len = FIX2INT(arg_post_len);
    05403         iseq->arg_post_start = FIX2INT(arg_post_start);
    05404         iseq->arg_block = FIX2INT(arg_block);
    05405         iseq->arg_opts = RARRAY_LENINT(arg_opt_labels);
    05406         iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
    05407
    05408         if (iseq->arg_block != -1) {
    05409             iseq->arg_size = iseq->arg_block + 1;
    05410         }
    05411         else if (iseq->arg_post_len) {
    05412             iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
    05413         }
    05414         else if (iseq->arg_rest != -1) {
    05415             iseq->arg_size = iseq->arg_rest + 1;
    05416         }
    05417         else {
    05418             iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
    05419         }
    05420
    05421         for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
    05422             iseq->arg_opt_table[i] =
    05423               (VALUE)register_label(iseq, labels_table,
    05424                                     rb_ary_entry(arg_opt_labels, i));
    05425         }
    05426
    05427         iseq->arg_simple = NUM2INT(arg_simple);
    05428     }
    05429
    05430     /* exception */
    05431     iseq_build_exception(iseq, labels_table, exception);
    05432
    05433     /* body */
    05434     iseq_build_body(iseq, anchor, body, labels_table);
    05435     return iseq->self;
    05436 }
    05437
    05438 /* for parser */
    05439
    05440 int
    05441 rb_dvar_defined(ID id)
    05442 {
    05443     rb_thread_t *th = GET_THREAD();
    05444     rb_iseq_t *iseq;
    05445     if (th->base_block && (iseq = th->base_block->iseq)) {
    05446         while (iseq->type == ISEQ_TYPE_BLOCK ||
    05447                iseq->type == ISEQ_TYPE_RESCUE ||
    05448                iseq->type == ISEQ_TYPE_ENSURE ||
    05449                iseq->type == ISEQ_TYPE_EVAL ||
    05450                iseq->type == ISEQ_TYPE_MAIN
    05451                ) {
    05452             int i;
    05453
    05454             for (i = 0; i < iseq->local_table_size; i++) {
    05455                 if (iseq->local_table[i] == id) {
    05456                     return 1;
    05457                 }
    05458             }
    05459             iseq = iseq->parent_iseq;
    05460         }
    05461     }
    05462     return 0;
    05463 }
    05464
    05465 int
    05466 rb_local_defined(ID id)
    05467 {
    05468     rb_thread_t *th = GET_THREAD();
    05469     rb_iseq_t *iseq;
    05470
    05471     if (th->base_block && th->base_block->iseq) {
    05472         int i;
    05473         iseq = th->base_block->iseq->local_iseq;
    05474
    05475         for (i=0; i<iseq->local_table_size; i++) {
    05476             if (iseq->local_table[i] == id) {
    05477                 return 1;
    05478             }
    05479         }
    05480     }
    05481     return 0;
    05482 }
    05483
    05484 int
    05485 rb_parse_in_eval(void)
    05486 {
    05487     return GET_THREAD()->parse_in_eval > 0;
    05488 }
    05489
    05490 int
    05491 rb_parse_in_main(void)
    05492 {
    05493     return GET_THREAD()->parse_in_eval < 0;
    05494 }
    05495