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