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 iseq->compile_data->last_line = line = (int)nd_line(node);
03268 debug_node_start(node);
03269
03270 type = nd_type(node);
03271
03272 if (node->flags & NODE_FL_NEWLINE) {
03273 ADD_TRACE(ret, line, RUBY_EVENT_LINE);
03274 saved_last_element = ret->last;
03275 }
03276
03277 switch (type) {
03278 case NODE_BLOCK:{
03279 while (node && nd_type(node) == NODE_BLOCK) {
03280 COMPILE_(ret, "BLOCK body", node->nd_head,
03281 (node->nd_next == 0 && poped == 0) ? 0 : 1);
03282 node = node->nd_next;
03283 }
03284 if (node) {
03285 COMPILE_(ret, "BLOCK next", node->nd_next, poped);
03286 }
03287 break;
03288 }
03289 case NODE_IF:{
03290 DECL_ANCHOR(cond_seq);
03291 DECL_ANCHOR(then_seq);
03292 DECL_ANCHOR(else_seq);
03293 LABEL *then_label, *else_label, *end_label;
03294
03295 INIT_ANCHOR(cond_seq);
03296 INIT_ANCHOR(then_seq);
03297 INIT_ANCHOR(else_seq);
03298 then_label = NEW_LABEL(line);
03299 else_label = NEW_LABEL(line);
03300 end_label = NEW_LABEL(line);
03301
03302 compile_branch_condition(iseq, cond_seq, node->nd_cond,
03303 then_label, else_label);
03304 COMPILE_(then_seq, "then", node->nd_body, poped);
03305 COMPILE_(else_seq, "else", node->nd_else, poped);
03306
03307 ADD_SEQ(ret, cond_seq);
03308
03309 ADD_LABEL(ret, then_label);
03310 ADD_SEQ(ret, then_seq);
03311 ADD_INSNL(ret, line, jump, end_label);
03312
03313 ADD_LABEL(ret, else_label);
03314 ADD_SEQ(ret, else_seq);
03315
03316 ADD_LABEL(ret, end_label);
03317
03318 break;
03319 }
03320 case NODE_CASE:{
03321 NODE *vals;
03322 NODE *tempnode = node;
03323 LABEL *endlabel, *elselabel;
03324 DECL_ANCHOR(head);
03325 DECL_ANCHOR(body_seq);
03326 DECL_ANCHOR(cond_seq);
03327 int only_special_literals = 1;
03328 VALUE literals = rb_hash_new();
03329
03330 INIT_ANCHOR(head);
03331 INIT_ANCHOR(body_seq);
03332 INIT_ANCHOR(cond_seq);
03333
03334 rb_hash_tbl_raw(literals)->type = &cdhash_type;
03335
03336 if (node->nd_head == 0) {
03337 COMPILE_(ret, "when", node->nd_body, poped);
03338 break;
03339 }
03340 COMPILE(head, "case base", node->nd_head);
03341
03342 node = node->nd_body;
03343 type = nd_type(node);
03344 line = nd_line(node);
03345
03346 if (type != NODE_WHEN) {
03347 COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type)));
03348 }
03349
03350 endlabel = NEW_LABEL(line);
03351 elselabel = NEW_LABEL(line);
03352
03353 ADD_SEQ(ret, head);
03354
03355 while (type == NODE_WHEN) {
03356 LABEL *l1;
03357
03358 l1 = NEW_LABEL(line);
03359 ADD_LABEL(body_seq, l1);
03360 ADD_INSN(body_seq, line, pop);
03361 COMPILE_(body_seq, "when body", node->nd_body, poped);
03362 ADD_INSNL(body_seq, line, jump, endlabel);
03363
03364 vals = node->nd_head;
03365 if (vals) {
03366 switch (nd_type(vals)) {
03367 case NODE_ARRAY:
03368 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
03369 break;
03370 case NODE_SPLAT:
03371 case NODE_ARGSCAT:
03372 case NODE_ARGSPUSH:
03373 only_special_literals = 0;
03374 ADD_INSN (cond_seq, nd_line(vals), dup);
03375 COMPILE(cond_seq, "when/cond splat", vals);
03376 ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
03377 ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
03378 break;
03379 default:
03380 rb_bug("NODE_CASE: unknown node (%s)",
03381 ruby_node_name(nd_type(vals)));
03382 }
03383 }
03384 else {
03385 rb_bug("NODE_CASE: must be NODE_ARRAY, but 0");
03386 }
03387
03388 node = node->nd_next;
03389 if (!node) {
03390 break;
03391 }
03392 type = nd_type(node);
03393 line = nd_line(node);
03394 }
03395
03396 if (node) {
03397 ADD_LABEL(cond_seq, elselabel);
03398 ADD_INSN(cond_seq, line, pop);
03399 COMPILE_(cond_seq, "else", node, poped);
03400 ADD_INSNL(cond_seq, line, jump, endlabel);
03401 }
03402 else {
03403 debugs("== else (implicit)\n");
03404 ADD_LABEL(cond_seq, elselabel);
03405 ADD_INSN(cond_seq, nd_line(tempnode), pop);
03406 if (!poped) {
03407 ADD_INSN(cond_seq, nd_line(tempnode), putnil);
03408 }
03409 ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
03410 }
03411
03412 if (only_special_literals) {
03413 iseq_add_mark_object(iseq, literals);
03414
03415 ADD_INSN(ret, nd_line(tempnode), dup);
03416 ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, literals, elselabel);
03417 }
03418
03419 ADD_SEQ(ret, cond_seq);
03420 ADD_SEQ(ret, body_seq);
03421 ADD_LABEL(ret, endlabel);
03422 break;
03423 }
03424 case NODE_WHEN:{
03425 NODE *vals;
03426 NODE *val;
03427 NODE *orig_node = node;
03428 LABEL *endlabel;
03429 DECL_ANCHOR(body_seq);
03430
03431 INIT_ANCHOR(body_seq);
03432 endlabel = NEW_LABEL(line);
03433
03434 while (node && nd_type(node) == NODE_WHEN) {
03435 LABEL *l1 = NEW_LABEL(line = nd_line(node));
03436 ADD_LABEL(body_seq, l1);
03437 COMPILE_(body_seq, "when", node->nd_body, poped);
03438 ADD_INSNL(body_seq, line, jump, endlabel);
03439
03440 vals = node->nd_head;
03441 if (!vals) {
03442 rb_bug("NODE_WHEN: must be NODE_ARRAY, but 0");
03443 }
03444 switch (nd_type(vals)) {
03445 case NODE_ARRAY:
03446 while (vals) {
03447 val = vals->nd_head;
03448 COMPILE(ret, "when2", val);
03449 ADD_INSNL(ret, nd_line(val), branchif, l1);
03450 vals = vals->nd_next;
03451 }
03452 break;
03453 case NODE_SPLAT:
03454 case NODE_ARGSCAT:
03455 case NODE_ARGSPUSH:
03456 ADD_INSN(ret, nd_line(vals), putnil);
03457 COMPILE(ret, "when2/cond splat", vals);
03458 ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
03459 ADD_INSNL(ret, nd_line(vals), branchif, l1);
03460 break;
03461 default:
03462 rb_bug("NODE_WHEN: unknown node (%s)",
03463 ruby_node_name(nd_type(vals)));
03464 }
03465 node = node->nd_next;
03466 }
03467
03468 COMPILE_(ret, "else", node, poped);
03469 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
03470
03471 ADD_SEQ(ret, body_seq);
03472 ADD_LABEL(ret, endlabel);
03473
03474 break;
03475 }
03476 case NODE_OPT_N:
03477 case NODE_WHILE:
03478 case NODE_UNTIL:{
03479 LABEL *prev_start_label = iseq->compile_data->start_label;
03480 LABEL *prev_end_label = iseq->compile_data->end_label;
03481 LABEL *prev_redo_label = iseq->compile_data->redo_label;
03482 int prev_loopval_popped = iseq->compile_data->loopval_popped;
03483
03484 struct iseq_compile_data_ensure_node_stack enl;
03485
03486 LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(line);
03487 LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(line);
03488 LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line);
03489 LABEL *end_label = NEW_LABEL(line);
03490
03491 LABEL *next_catch_label = NEW_LABEL(line);
03492 LABEL *tmp_label = NULL;
03493
03494 iseq->compile_data->loopval_popped = 0;
03495 push_ensure_entry(iseq, &enl, 0, 0);
03496
03497 if (type == NODE_OPT_N || node->nd_state == 1) {
03498 ADD_INSNL(ret, line, jump, next_label);
03499 }
03500 else {
03501 tmp_label = NEW_LABEL(line);
03502 ADD_INSNL(ret, line, jump, tmp_label);
03503 }
03504 ADD_INSN(ret, line, putnil);
03505 ADD_LABEL(ret, next_catch_label);
03506 ADD_INSN(ret, line, pop);
03507 ADD_INSNL(ret, line, jump, next_label);
03508 if (tmp_label) ADD_LABEL(ret, tmp_label);
03509
03510 ADD_LABEL(ret, redo_label);
03511 COMPILE_POPED(ret, "while body", node->nd_body);
03512 ADD_LABEL(ret, next_label);
03513
03514 if (type == NODE_WHILE) {
03515 compile_branch_condition(iseq, ret, node->nd_cond,
03516 redo_label, end_label);
03517 }
03518 else if (type == NODE_UNTIL) {
03519
03520 compile_branch_condition(iseq, ret, node->nd_cond,
03521 end_label, redo_label);
03522 }
03523 else {
03524 ADD_CALL_RECEIVER(ret, line);
03525 ADD_CALL(ret, line, ID2SYM(idGets), INT2FIX(0));
03526 ADD_INSNL(ret, line, branchif, redo_label);
03527
03528 }
03529
03530 ADD_LABEL(ret, end_label);
03531
03532 if (node->nd_state == Qundef) {
03533
03534 rb_bug("unsupported: putundef");
03535 }
03536 else {
03537 ADD_INSN(ret, line, putnil);
03538 }
03539
03540 ADD_LABEL(ret, break_label);
03541
03542 if (poped) {
03543 ADD_INSN(ret, line, pop);
03544 }
03545
03546 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label,
03547 0, break_label);
03548 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, 0,
03549 next_catch_label);
03550 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0,
03551 iseq->compile_data->redo_label);
03552
03553 iseq->compile_data->start_label = prev_start_label;
03554 iseq->compile_data->end_label = prev_end_label;
03555 iseq->compile_data->redo_label = prev_redo_label;
03556 iseq->compile_data->loopval_popped = prev_loopval_popped;
03557 iseq->compile_data->ensure_node_stack = iseq->compile_data->ensure_node_stack->prev;
03558 break;
03559 }
03560 case NODE_ITER:
03561 case NODE_FOR:{
03562 VALUE prevblock = iseq->compile_data->current_block;
03563 LABEL *retry_label = NEW_LABEL(line);
03564 LABEL *retry_end_l = NEW_LABEL(line);
03565
03566 ADD_LABEL(ret, retry_label);
03567 if (nd_type(node) == NODE_FOR) {
03568 COMPILE(ret, "iter caller (for)", node->nd_iter);
03569
03570 iseq->compile_data->current_block =
03571 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
03572 ISEQ_TYPE_BLOCK, line);
03573
03574 ADD_SEND_R(ret, line, ID2SYM(idEach), INT2FIX(0),
03575 iseq->compile_data->current_block, INT2FIX(0));
03576 }
03577 else {
03578 iseq->compile_data->current_block =
03579 NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
03580 ISEQ_TYPE_BLOCK, line);
03581 COMPILE(ret, "iter caller", node->nd_iter);
03582 }
03583 ADD_LABEL(ret, retry_end_l);
03584
03585 if (poped) {
03586 ADD_INSN(ret, line, pop);
03587 }
03588
03589 iseq->compile_data->current_block = prevblock;
03590
03591 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l);
03592
03593 break;
03594 }
03595 case NODE_BREAK:{
03596 unsigned long level = 0;
03597
03598 if (iseq->compile_data->redo_label != 0) {
03599
03600 LABEL *splabel = NEW_LABEL(0);
03601 ADD_LABEL(ret, splabel);
03602 ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03603 COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped);
03604 add_ensure_iseq(ret, iseq, 0);
03605 ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
03606 ADD_ADJUST_RESTORE(ret, splabel);
03607
03608 if (!poped) {
03609 ADD_INSN(ret, line, putnil);
03610 }
03611 }
03612 else if (iseq->type == ISEQ_TYPE_BLOCK) {
03613 break_by_insn:
03614
03615 COMPILE(ret, "break val (block)", node->nd_stts);
03616 ADD_INSN1(ret, line, throw, INT2FIX(level | 0x02) );
03617 if (poped) {
03618 ADD_INSN(ret, line, pop);
03619 }
03620 }
03621 else if (iseq->type == ISEQ_TYPE_EVAL) {
03622 break_in_eval:
03623 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break"));
03624 }
03625 else {
03626 rb_iseq_t *ip = iseq->parent_iseq;
03627 while (ip) {
03628 if (!ip->compile_data) {
03629 ip = 0;
03630 break;
03631 }
03632
03633 level++;
03634 if (ip->compile_data->redo_label != 0) {
03635 level = 0x8000;
03636 if (ip->compile_data->loopval_popped == 0) {
03637
03638 level |= 0x4000;
03639 }
03640 goto break_by_insn;
03641 }
03642 else if (ip->type == ISEQ_TYPE_BLOCK) {
03643 level <<= 16;
03644 goto break_by_insn;
03645 }
03646 else if (ip->type == ISEQ_TYPE_EVAL) {
03647 goto break_in_eval;
03648 }
03649
03650 ip = ip->parent_iseq;
03651 }
03652 COMPILE_ERROR((ERROR_ARGS "Invalid break"));
03653 }
03654 break;
03655 }
03656 case NODE_NEXT:{
03657 unsigned long level = 0;
03658
03659 if (iseq->compile_data->redo_label != 0) {
03660 LABEL *splabel = NEW_LABEL(0);
03661 debugs("next in while loop\n");
03662 ADD_LABEL(ret, splabel);
03663 COMPILE(ret, "next val/valid syntax?", node->nd_stts);
03664 add_ensure_iseq(ret, iseq, 0);
03665 ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03666 ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
03667 ADD_ADJUST_RESTORE(ret, splabel);
03668 if (!poped) {
03669 ADD_INSN(ret, line, putnil);
03670 }
03671 }
03672 else if (iseq->compile_data->end_label) {
03673 LABEL *splabel = NEW_LABEL(0);
03674 debugs("next in block\n");
03675 ADD_LABEL(ret, splabel);
03676 ADD_ADJUST(ret, line, iseq->compile_data->start_label);
03677 COMPILE(ret, "next val", node->nd_stts);
03678 add_ensure_iseq(ret, iseq, 0);
03679 ADD_INSNL(ret, line, jump, iseq->compile_data->end_label);
03680 ADD_ADJUST_RESTORE(ret, splabel);
03681
03682 if (!poped) {
03683 ADD_INSN(ret, line, putnil);
03684 }
03685 }
03686 else if (iseq->type == ISEQ_TYPE_EVAL) {
03687 next_in_eval:
03688 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
03689 }
03690 else {
03691 rb_iseq_t *ip;
03692 ip = iseq;
03693 while (ip) {
03694 if (!ip->compile_data) {
03695 ip = 0;
03696 break;
03697 }
03698
03699 level = 0x8000 | 0x4000;
03700 if (ip->compile_data->redo_label != 0) {
03701
03702 break;
03703 }
03704 else if (ip->type == ISEQ_TYPE_BLOCK) {
03705 break;
03706 }
03707 else if (ip->type == ISEQ_TYPE_EVAL) {
03708 goto next_in_eval;
03709 }
03710
03711 ip = ip->parent_iseq;
03712 }
03713 if (ip != 0) {
03714 COMPILE(ret, "next val", node->nd_stts);
03715 ADD_INSN1(ret, line, throw, INT2FIX(level | 0x03) );
03716
03717 if (poped) {
03718 ADD_INSN(ret, line, pop);
03719 }
03720 }
03721 else {
03722 COMPILE_ERROR((ERROR_ARGS "Invalid next"));
03723 }
03724 }
03725 break;
03726 }
03727 case NODE_REDO:{
03728 if (iseq->compile_data->redo_label) {
03729 LABEL *splabel = NEW_LABEL(0);
03730 debugs("redo in while");
03731 ADD_LABEL(ret, splabel);
03732 ADD_ADJUST(ret, line, iseq->compile_data->redo_label);
03733 add_ensure_iseq(ret, iseq, 0);
03734 ADD_INSNL(ret, line, jump, iseq->compile_data->redo_label);
03735 ADD_ADJUST_RESTORE(ret, splabel);
03736 if (!poped) {
03737 ADD_INSN(ret, line, putnil);
03738 }
03739 }
03740 else if (iseq->type == ISEQ_TYPE_EVAL) {
03741 redo_in_eval:
03742 COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
03743 }
03744 else if (iseq->compile_data->start_label) {
03745 LABEL *splabel = NEW_LABEL(0);
03746
03747 debugs("redo in block");
03748 ADD_LABEL(ret, splabel);
03749 add_ensure_iseq(ret, iseq, 0);
03750 ADD_ADJUST(ret, line, iseq->compile_data->start_label);
03751 ADD_INSNL(ret, line, jump, iseq->compile_data->start_label);
03752 ADD_ADJUST_RESTORE(ret, splabel);
03753
03754 if (!poped) {
03755 ADD_INSN(ret, line, putnil);
03756 }
03757 }
03758 else {
03759 rb_iseq_t *ip;
03760 unsigned long level;
03761 level = 0x8000 | 0x4000;
03762 ip = iseq;
03763 while (ip) {
03764 if (!ip->compile_data) {
03765 ip = 0;
03766 break;
03767 }
03768
03769 if (ip->compile_data->redo_label != 0) {
03770 break;
03771 }
03772 else if (ip->type == ISEQ_TYPE_BLOCK) {
03773 break;
03774 }
03775 else if (ip->type == ISEQ_TYPE_EVAL) {
03776 goto redo_in_eval;
03777 }
03778
03779 ip = ip->parent_iseq;
03780 }
03781 if (ip != 0) {
03782 ADD_INSN(ret, line, putnil);
03783 ADD_INSN1(ret, line, throw, INT2FIX(level | 0x05) );
03784
03785 if (poped) {
03786 ADD_INSN(ret, line, pop);
03787 }
03788 }
03789 else {
03790 COMPILE_ERROR((ERROR_ARGS "Invalid redo"));
03791 }
03792 }
03793 break;
03794 }
03795 case NODE_RETRY:{
03796 if (iseq->type == ISEQ_TYPE_RESCUE) {
03797 ADD_INSN(ret, line, putnil);
03798 ADD_INSN1(ret, line, throw, INT2FIX(0x04) );
03799
03800 if (poped) {
03801 ADD_INSN(ret, line, pop);
03802 }
03803 }
03804 else {
03805 COMPILE_ERROR((ERROR_ARGS "Invalid retry"));
03806 }
03807 break;
03808 }
03809 case NODE_BEGIN:{
03810 COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped);
03811 break;
03812 }
03813 case NODE_RESCUE:{
03814 LABEL *lstart = NEW_LABEL(line);
03815 LABEL *lend = NEW_LABEL(line);
03816 LABEL *lcont = NEW_LABEL(line);
03817 VALUE rescue = NEW_CHILD_ISEQVAL(
03818 node->nd_resq,
03819 rb_str_concat(rb_str_new2("rescue in "), iseq->location.label),
03820 ISEQ_TYPE_RESCUE, line);
03821
03822 ADD_LABEL(ret, lstart);
03823 COMPILE(ret, "rescue head", node->nd_head);
03824 ADD_LABEL(ret, lend);
03825 if (node->nd_else) {
03826 ADD_INSN(ret, line, pop);
03827 COMPILE(ret, "rescue else", node->nd_else);
03828 }
03829 ADD_INSN(ret, line, nop);
03830 ADD_LABEL(ret, lcont);
03831
03832 if (poped) {
03833 ADD_INSN(ret, line, pop);
03834 }
03835
03836
03837 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
03838 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart);
03839 break;
03840 }
03841 case NODE_RESBODY:{
03842 NODE *resq = node;
03843 NODE *narg;
03844 LABEL *label_miss, *label_hit;
03845
03846 while (resq) {
03847 label_miss = NEW_LABEL(line);
03848 label_hit = NEW_LABEL(line);
03849
03850 narg = resq->nd_args;
03851 if (narg) {
03852 switch (nd_type(narg)) {
03853 case NODE_ARRAY:
03854 while (narg) {
03855 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03856 COMPILE(ret, "rescue arg", narg->nd_head);
03857 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
03858 ADD_INSNL(ret, line, branchif, label_hit);
03859 narg = narg->nd_next;
03860 }
03861 break;
03862 case NODE_SPLAT:
03863 case NODE_ARGSCAT:
03864 case NODE_ARGSPUSH:
03865 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03866 COMPILE(ret, "rescue/cond splat", narg);
03867 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
03868 ADD_INSNL(ret, line, branchif, label_hit);
03869 break;
03870 default:
03871 rb_bug("NODE_RESBODY: unknown node (%s)",
03872 ruby_node_name(nd_type(narg)));
03873 }
03874 }
03875 else {
03876 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
03877 ADD_INSN1(ret, line, putobject, rb_eStandardError);
03878 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
03879 ADD_INSNL(ret, line, branchif, label_hit);
03880 }
03881 ADD_INSNL(ret, line, jump, label_miss);
03882 ADD_LABEL(ret, label_hit);
03883 COMPILE(ret, "resbody body", resq->nd_body);
03884 if (iseq->compile_data->option->tailcall_optimization) {
03885 ADD_INSN(ret, line, nop);
03886 }
03887 ADD_INSN(ret, line, leave);
03888 ADD_LABEL(ret, label_miss);
03889 resq = resq->nd_head;
03890 }
03891 break;
03892 }
03893 case NODE_ENSURE:{
03894 DECL_ANCHOR(ensr);
03895 VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr,
03896 rb_str_concat(rb_str_new2
03897 ("ensure in "),
03898 iseq->location.label),
03899 ISEQ_TYPE_ENSURE, line);
03900 LABEL *lstart = NEW_LABEL(line);
03901 LABEL *lend = NEW_LABEL(line);
03902 LABEL *lcont = NEW_LABEL(line);
03903 struct ensure_range er;
03904 struct iseq_compile_data_ensure_node_stack enl;
03905 struct ensure_range *erange;
03906
03907 INIT_ANCHOR(ensr);
03908 COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
03909
03910 er.begin = lstart;
03911 er.end = lend;
03912 er.next = 0;
03913 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
03914
03915 ADD_LABEL(ret, lstart);
03916 COMPILE_(ret, "ensure head", node->nd_head, poped);
03917 ADD_LABEL(ret, lend);
03918 if (ensr->anchor.next == 0) {
03919 ADD_INSN(ret, line, nop);
03920 }
03921 else {
03922 ADD_SEQ(ret, ensr);
03923 }
03924 ADD_LABEL(ret, lcont);
03925
03926 erange = iseq->compile_data->ensure_node_stack->erange;
03927 while (erange) {
03928 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
03929 ensure, lcont);
03930 erange = erange->next;
03931 }
03932
03933 iseq->compile_data->ensure_node_stack = enl.prev;
03934 break;
03935 }
03936
03937 case NODE_AND:
03938 case NODE_OR:{
03939 LABEL *end_label = NEW_LABEL(line);
03940 COMPILE(ret, "nd_1st", node->nd_1st);
03941 if (!poped) {
03942 ADD_INSN(ret, line, dup);
03943 }
03944 if (type == NODE_AND) {
03945 ADD_INSNL(ret, line, branchunless, end_label);
03946 }
03947 else {
03948 ADD_INSNL(ret, line, branchif, end_label);
03949 }
03950 if (!poped) {
03951 ADD_INSN(ret, line, pop);
03952 }
03953 COMPILE_(ret, "nd_2nd", node->nd_2nd, poped);
03954 ADD_LABEL(ret, end_label);
03955 break;
03956 }
03957
03958 case NODE_MASGN:{
03959 compile_massign(iseq, ret, node, poped);
03960 break;
03961 }
03962
03963 case NODE_LASGN:{
03964 ID id = node->nd_vid;
03965 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
03966
03967 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
03968 COMPILE(ret, "rvalue", node->nd_value);
03969
03970 if (!poped) {
03971 ADD_INSN(ret, line, dup);
03972 }
03973 ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
03974
03975 break;
03976 }
03977 case NODE_DASGN:
03978 case NODE_DASGN_CURR:{
03979 int idx, lv, ls;
03980 COMPILE(ret, "dvalue", node->nd_value);
03981 debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*"));
03982
03983 if (!poped) {
03984 ADD_INSN(ret, line, dup);
03985 }
03986
03987 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
03988
03989 if (idx < 0) {
03990 rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid));
03991 }
03992
03993 ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
03994 break;
03995 }
03996 case NODE_GASGN:{
03997 COMPILE(ret, "lvalue", node->nd_value);
03998
03999 if (!poped) {
04000 ADD_INSN(ret, line, dup);
04001 }
04002 ADD_INSN1(ret, line, setglobal,
04003 ((VALUE)node->nd_entry | 1));
04004 break;
04005 }
04006 case NODE_IASGN:
04007 case NODE_IASGN2:{
04008 COMPILE(ret, "lvalue", node->nd_value);
04009 if (!poped) {
04010 ADD_INSN(ret, line, dup);
04011 }
04012 ADD_INSN2(ret, line, setinstancevariable,
04013 ID2SYM(node->nd_vid), INT2FIX(iseq->is_size++));
04014 break;
04015 }
04016 case NODE_CDECL:{
04017 COMPILE(ret, "lvalue", node->nd_value);
04018
04019 if (!poped) {
04020 ADD_INSN(ret, line, dup);
04021 }
04022
04023 if (node->nd_vid) {
04024 ADD_INSN1(ret, line, putspecialobject,
04025 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
04026 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
04027 }
04028 else {
04029 compile_cpath(ret, iseq, node->nd_else);
04030 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
04031 }
04032 break;
04033 }
04034 case NODE_CVASGN:{
04035 COMPILE(ret, "cvasgn val", node->nd_value);
04036 if (!poped) {
04037 ADD_INSN(ret, line, dup);
04038 }
04039 ADD_INSN1(ret, line, setclassvariable,
04040 ID2SYM(node->nd_vid));
04041 break;
04042 }
04043 case NODE_OP_ASGN1: {
04044 DECL_ANCHOR(args);
04045 VALUE argc;
04046 VALUE flag = 0;
04047 ID id = node->nd_mid;
04048 int boff = 0;
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073 if (!poped) {
04074 ADD_INSN(ret, line, putnil);
04075 }
04076 COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv);
04077 switch (nd_type(node->nd_args->nd_head)) {
04078 case NODE_ZARRAY:
04079 argc = INT2FIX(0);
04080 break;
04081 case NODE_BLOCK_PASS:
04082 boff = 1;
04083 default:
04084 INIT_ANCHOR(args);
04085 argc = setup_args(iseq, args, node->nd_args->nd_head, &flag);
04086 ADD_SEQ(ret, args);
04087 }
04088 ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
04089 ADD_SEND_R(ret, line, ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag));
04090
04091 if (id == 0 || id == 1) {
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101 LABEL *label = NEW_LABEL(line);
04102 LABEL *lfin = NEW_LABEL(line);
04103
04104 ADD_INSN(ret, line, dup);
04105 if (id == 0) {
04106
04107 ADD_INSNL(ret, line, branchif, label);
04108 }
04109 else {
04110
04111 ADD_INSNL(ret, line, branchunless, label);
04112 }
04113 ADD_INSN(ret, line, pop);
04114
04115 COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
04116 if (!poped) {
04117 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04118 }
04119 if (flag & VM_CALL_ARGS_SPLAT) {
04120 ADD_INSN1(ret, line, newarray, INT2FIX(1));
04121 if (boff > 0) {
04122 ADD_INSN1(ret, line, dupn, INT2FIX(3));
04123 ADD_INSN(ret, line, swap);
04124 ADD_INSN(ret, line, pop);
04125 }
04126 ADD_INSN(ret, line, concatarray);
04127 if (boff > 0) {
04128 ADD_INSN1(ret, line, setn, INT2FIX(3));
04129 ADD_INSN(ret, line, pop);
04130 ADD_INSN(ret, line, pop);
04131 }
04132 ADD_SEND_R(ret, line, ID2SYM(idASET),
04133 argc, Qfalse, LONG2FIX(flag));
04134 }
04135 else {
04136 if (boff > 0)
04137 ADD_INSN(ret, line, swap);
04138 ADD_SEND_R(ret, line, ID2SYM(idASET),
04139 FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
04140 }
04141 ADD_INSN(ret, line, pop);
04142 ADD_INSNL(ret, line, jump, lfin);
04143 ADD_LABEL(ret, label);
04144 if (!poped) {
04145 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04146 }
04147 ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
04148 ADD_LABEL(ret, lfin);
04149 }
04150 else {
04151 COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body);
04152 ADD_SEND(ret, line, ID2SYM(id), INT2FIX(1));
04153 if (!poped) {
04154 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
04155 }
04156 if (flag & VM_CALL_ARGS_SPLAT) {
04157 ADD_INSN1(ret, line, newarray, INT2FIX(1));
04158 if (boff > 0) {
04159 ADD_INSN1(ret, line, dupn, INT2FIX(3));
04160 ADD_INSN(ret, line, swap);
04161 ADD_INSN(ret, line, pop);
04162 }
04163 ADD_INSN(ret, line, concatarray);
04164 if (boff > 0) {
04165 ADD_INSN1(ret, line, setn, INT2FIX(3));
04166 ADD_INSN(ret, line, pop);
04167 ADD_INSN(ret, line, pop);
04168 }
04169 ADD_SEND_R(ret, line, ID2SYM(idASET),
04170 argc, Qfalse, LONG2FIX(flag));
04171 }
04172 else {
04173 if (boff > 0)
04174 ADD_INSN(ret, line, swap);
04175 ADD_SEND_R(ret, line, ID2SYM(idASET),
04176 FIXNUM_INC(argc, 1), Qfalse, LONG2FIX(flag));
04177 }
04178 ADD_INSN(ret, line, pop);
04179 }
04180
04181 break;
04182 }
04183 case NODE_OP_ASGN2:{
04184 ID atype = node->nd_next->nd_mid;
04185 LABEL *lfin = NEW_LABEL(line);
04186 LABEL *lcfin = NEW_LABEL(line);
04187
04188
04189
04190
04191
04192
04193
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 COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv);
04230 ADD_INSN(ret, line, dup);
04231 ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_vid),
04232 INT2FIX(0));
04233
04234 if (atype == 0 || atype == 1) {
04235 ADD_INSN(ret, line, dup);
04236 if (atype == 0) {
04237 ADD_INSNL(ret, line, branchif, lcfin);
04238 }
04239 else {
04240 ADD_INSNL(ret, line, branchunless, lcfin);
04241 }
04242 ADD_INSN(ret, line, pop);
04243 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
04244 ADD_INSN(ret, line, swap);
04245 ADD_INSN1(ret, line, topn, INT2FIX(1));
04246 ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
04247 INT2FIX(1));
04248 ADD_INSNL(ret, line, jump, lfin);
04249
04250 ADD_LABEL(ret, lcfin);
04251 ADD_INSN(ret, line, swap);
04252
04253 ADD_LABEL(ret, lfin);
04254 ADD_INSN(ret, line, pop);
04255 if (poped) {
04256
04257 ADD_INSN(ret, line, pop);
04258 }
04259 }
04260 else {
04261 COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
04262 ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_mid),
04263 INT2FIX(1));
04264 if (!poped) {
04265 ADD_INSN(ret, line, swap);
04266 ADD_INSN1(ret, line, topn, INT2FIX(1));
04267 }
04268 ADD_SEND(ret, line, ID2SYM(node->nd_next->nd_aid),
04269 INT2FIX(1));
04270 ADD_INSN(ret, line, pop);
04271 }
04272 break;
04273 }
04274 case NODE_OP_CDECL: {
04275 LABEL *lfin = 0;
04276 LABEL *lassign = 0;
04277 ID mid;
04278
04279 switch (nd_type(node->nd_head)) {
04280 case NODE_COLON3:
04281 ADD_INSN1(ret, line, putobject, rb_cObject);
04282 break;
04283 case NODE_COLON2:
04284 COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head);
04285 break;
04286 default:
04287 do {
04288 COMPILE_ERROR((ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
04289 ruby_node_name(nd_type(node->nd_head))));
04290 } while (0);
04291 return COMPILE_NG;
04292 }
04293 mid = node->nd_head->nd_mid;
04294
04295 if (node->nd_aid == 0) {
04296 lassign = NEW_LABEL(line);
04297 ADD_INSN(ret, line, dup);
04298 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
04299 ID2SYM(mid), Qfalse);
04300 ADD_INSNL(ret, line, branchunless, lassign);
04301 }
04302 ADD_INSN(ret, line, dup);
04303 ADD_INSN1(ret, line, getconstant, ID2SYM(mid));
04304
04305 if (node->nd_aid == 0 || node->nd_aid == 1) {
04306 lfin = NEW_LABEL(line);
04307 if (!poped) ADD_INSN(ret, line, dup);
04308 if (node->nd_aid == 0)
04309 ADD_INSNL(ret, line, branchif, lfin);
04310 else
04311 ADD_INSNL(ret, line, branchunless, lfin);
04312
04313 if (!poped) ADD_INSN(ret, line, pop);
04314 if (lassign) ADD_LABEL(ret, lassign);
04315 COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
04316
04317 if (poped)
04318 ADD_INSN1(ret, line, topn, INT2FIX(1));
04319 else {
04320 ADD_INSN1(ret, line, dupn, INT2FIX(2));
04321 ADD_INSN(ret, line, swap);
04322 }
04323 ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
04324 ADD_LABEL(ret, lfin);
04325 if (!poped) ADD_INSN(ret, line, swap);
04326 ADD_INSN(ret, line, pop);
04327 }
04328 else {
04329 COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value);
04330
04331 ADD_CALL(ret, line, ID2SYM(node->nd_aid), INT2FIX(1));
04332
04333 ADD_INSN(ret, line, swap);
04334 if (!poped) {
04335 ADD_INSN1(ret, line, topn, INT2FIX(1));
04336 ADD_INSN(ret, line, swap);
04337 }
04338 ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
04339 }
04340 break;
04341 }
04342 case NODE_OP_ASGN_AND:
04343 case NODE_OP_ASGN_OR:{
04344 LABEL *lfin = NEW_LABEL(line);
04345 LABEL *lassign;
04346
04347 if (nd_type(node) == NODE_OP_ASGN_OR) {
04348 LABEL *lfinish[2];
04349 lfinish[0] = lfin;
04350 lfinish[1] = 0;
04351 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
04352 lassign = lfinish[1];
04353 if (!lassign) {
04354 lassign = NEW_LABEL(line);
04355 }
04356 ADD_INSNL(ret, line, branchunless, lassign);
04357 }
04358 else {
04359 lassign = NEW_LABEL(line);
04360 }
04361
04362 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
04363 ADD_INSN(ret, line, dup);
04364
04365 if (nd_type(node) == NODE_OP_ASGN_AND) {
04366 ADD_INSNL(ret, line, branchunless, lfin);
04367 }
04368 else {
04369 ADD_INSNL(ret, line, branchif, lfin);
04370 }
04371
04372 ADD_INSN(ret, line, pop);
04373 ADD_LABEL(ret, lassign);
04374 COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
04375 ADD_LABEL(ret, lfin);
04376
04377 if (poped) {
04378
04379 ADD_INSN(ret, line, pop);
04380 }
04381 break;
04382 }
04383 case NODE_CALL:
04384 if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
04385 node->nd_mid == idFreeze && node->nd_args == NULL)
04386 {
04387 VALUE str = rb_fstring(node->nd_recv->nd_lit);
04388 iseq_add_mark_object(iseq, str);
04389 ADD_INSN1(ret, line, opt_str_freeze, str);
04390 if (poped) {
04391 ADD_INSN(ret, line, pop);
04392 }
04393 break;
04394 }
04395 case NODE_FCALL:
04396 case NODE_VCALL:{
04397
04398
04399
04400
04401
04402 DECL_ANCHOR(recv);
04403 DECL_ANCHOR(args);
04404 ID mid = node->nd_mid;
04405 VALUE argc;
04406 VALUE flag = 0;
04407 VALUE parent_block = iseq->compile_data->current_block;
04408 iseq->compile_data->current_block = Qfalse;
04409
04410 INIT_ANCHOR(recv);
04411 INIT_ANCHOR(args);
04412 #if SUPPORT_JOKE
04413 if (nd_type(node) == NODE_VCALL) {
04414 ID id_bitblt;
04415 ID id_answer;
04416
04417 CONST_ID(id_bitblt, "bitblt");
04418 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
04419
04420 if (mid == id_bitblt) {
04421 ADD_INSN(ret, line, bitblt);
04422 break;
04423 }
04424 else if (mid == id_answer) {
04425 ADD_INSN(ret, line, answer);
04426 break;
04427 }
04428 }
04429
04430 {
04431 ID goto_id;
04432 ID label_id;
04433
04434 CONST_ID(goto_id, "__goto__");
04435 CONST_ID(label_id, "__label__");
04436
04437 if (nd_type(node) == NODE_FCALL &&
04438 (mid == goto_id || mid == label_id)) {
04439 LABEL *label;
04440 st_data_t data;
04441 st_table *labels_table = iseq->compile_data->labels_table;
04442 ID label_name;
04443
04444 if (!labels_table) {
04445 labels_table = st_init_numtable();
04446 iseq->compile_data->labels_table = labels_table;
04447 }
04448 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
04449 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
04450
04451 label_name = SYM2ID(node->nd_args->nd_head->nd_lit);
04452 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
04453 label = NEW_LABEL(line);
04454 label->position = line;
04455 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
04456 }
04457 else {
04458 label = (LABEL *)data;
04459 }
04460 }
04461 else {
04462 COMPILE_ERROR((ERROR_ARGS "invalid goto/label format"));
04463 }
04464
04465
04466 if (mid == goto_id) {
04467 ADD_INSNL(ret, line, jump, label);
04468 }
04469 else {
04470 ADD_LABEL(ret, label);
04471 }
04472 break;
04473 }
04474 }
04475 #endif
04476
04477 if (type == NODE_CALL) {
04478 COMPILE(recv, "recv", node->nd_recv);
04479 }
04480 else if (type == NODE_FCALL || type == NODE_VCALL) {
04481 ADD_CALL_RECEIVER(recv, line);
04482 }
04483
04484
04485 if (nd_type(node) != NODE_VCALL) {
04486 argc = setup_args(iseq, args, node->nd_args, &flag);
04487 }
04488 else {
04489 argc = INT2FIX(0);
04490 }
04491
04492 ADD_SEQ(ret, recv);
04493 ADD_SEQ(ret, args);
04494
04495 debugp_param("call args argc", argc);
04496 debugp_param("call method", ID2SYM(mid));
04497
04498 switch (nd_type(node)) {
04499 case NODE_VCALL:
04500 flag |= VM_CALL_VCALL;
04501
04502 case NODE_FCALL:
04503 flag |= VM_CALL_FCALL;
04504 }
04505
04506 ADD_SEND_R(ret, line, ID2SYM(mid),
04507 argc, parent_block, LONG2FIX(flag));
04508
04509 if (poped) {
04510 ADD_INSN(ret, line, pop);
04511 }
04512 break;
04513 }
04514 case NODE_SUPER:
04515 case NODE_ZSUPER:{
04516 DECL_ANCHOR(args);
04517 int argc;
04518 VALUE flag = 0;
04519 VALUE parent_block = iseq->compile_data->current_block;
04520
04521 INIT_ANCHOR(args);
04522 iseq->compile_data->current_block = Qfalse;
04523 if (nd_type(node) == NODE_SUPER) {
04524 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag);
04525 argc = FIX2INT(vargc);
04526 }
04527 else {
04528
04529 int i;
04530 rb_iseq_t *liseq = iseq->local_iseq;
04531 int lvar_level = get_lvar_level(iseq);
04532
04533 argc = liseq->argc;
04534
04535
04536 for (i = 0; i < liseq->argc; i++) {
04537 int idx = liseq->local_size - i;
04538 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04539 }
04540
04541 if (!liseq->arg_simple) {
04542 if (liseq->arg_opts) {
04543
04544 int j;
04545 for (j = 0; j < liseq->arg_opts - 1; j++) {
04546 int idx = liseq->local_size - (i + j);
04547 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04548 }
04549 i += j;
04550 argc = i;
04551 }
04552
04553 if (liseq->arg_rest != -1) {
04554
04555 int idx = liseq->local_size - liseq->arg_rest;
04556 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04557 argc = liseq->arg_rest + 1;
04558 flag |= VM_CALL_ARGS_SPLAT;
04559 }
04560
04561 if (liseq->arg_post_len) {
04562
04563 int post_len = liseq->arg_post_len;
04564 int post_start = liseq->arg_post_start;
04565
04566 if (liseq->arg_rest != -1) {
04567 int j;
04568 for (j=0; j<post_len; j++) {
04569 int idx = liseq->local_size - (post_start + j);
04570 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04571 }
04572 ADD_INSN1(args, line, newarray, INT2FIX(j));
04573 ADD_INSN (args, line, concatarray);
04574
04575 }
04576 else {
04577 int j;
04578 for (j=0; j<post_len; j++) {
04579 int idx = liseq->local_size - (post_start + j);
04580 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04581 }
04582 argc = post_len + post_start;
04583 }
04584 }
04585
04586 if (liseq->arg_keyword >= 0) {
04587 int local_size = liseq->local_size;
04588 int idx = local_size - liseq->arg_keyword;
04589 argc++;
04590 ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04591 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04592 ADD_SEND (args, line, ID2SYM(rb_intern("dup")), INT2FIX(0));
04593 for (i = 0; i < liseq->arg_keywords; ++i) {
04594 ID id = liseq->arg_keyword_table[i];
04595 idx = local_size - get_local_var_idx(liseq, id);
04596 ADD_INSN1(args, line, putobject, ID2SYM(id));
04597 ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
04598 }
04599 ADD_SEND(args, line, ID2SYM(id_core_hash_merge_ptr), INT2FIX(i * 2 + 1));
04600 if (liseq->arg_rest != -1) {
04601 ADD_INSN1(args, line, newarray, INT2FIX(1));
04602 ADD_INSN (args, line, concatarray);
04603 --argc;
04604 }
04605 }
04606 }
04607 }
04608
04609
04610 ADD_INSN1(ret, line, putobject, nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
04611 ADD_SEQ(ret, args);
04612 ADD_INSN1(ret, line, invokesuper, new_callinfo(iseq, 0, argc, parent_block,
04613 flag | VM_CALL_SUPER | VM_CALL_FCALL));
04614
04615 if (poped) {
04616 ADD_INSN(ret, line, pop);
04617 }
04618 break;
04619 }
04620 case NODE_ARRAY:{
04621 compile_array_(iseq, ret, node, COMPILE_ARRAY_TYPE_ARRAY, poped);
04622 break;
04623 }
04624 case NODE_ZARRAY:{
04625 if (!poped) {
04626 ADD_INSN1(ret, line, newarray, INT2FIX(0));
04627 }
04628 break;
04629 }
04630 case NODE_VALUES:{
04631 NODE *n = node;
04632 while (n) {
04633 COMPILE(ret, "values item", n->nd_head);
04634 n = n->nd_next;
04635 }
04636 ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
04637 if (poped) {
04638 ADD_INSN(ret, line, pop);
04639 }
04640 break;
04641 }
04642 case NODE_HASH:{
04643 DECL_ANCHOR(list);
04644 int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
04645
04646 INIT_ANCHOR(list);
04647 switch (type) {
04648 case NODE_ARRAY:
04649 compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH);
04650 ADD_SEQ(ret, list);
04651 break;
04652
04653 case NODE_ZARRAY:
04654 ADD_INSN1(ret, line, newhash, INT2FIX(0));
04655 break;
04656
04657 default:
04658 rb_bug("can't make hash with this node: %s", ruby_node_name(type));
04659 }
04660
04661 if (poped) {
04662 ADD_INSN(ret, line, pop);
04663 }
04664 break;
04665 }
04666 case NODE_RETURN:{
04667 rb_iseq_t *is = iseq;
04668
04669 if (is) {
04670 if (is->type == ISEQ_TYPE_TOP) {
04671 COMPILE_ERROR((ERROR_ARGS "Invalid return"));
04672 }
04673 else {
04674 LABEL *splabel = 0;
04675
04676 if (is->type == ISEQ_TYPE_METHOD) {
04677 splabel = NEW_LABEL(0);
04678 ADD_LABEL(ret, splabel);
04679 ADD_ADJUST(ret, line, 0);
04680 }
04681
04682 COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
04683
04684 if (is->type == ISEQ_TYPE_METHOD) {
04685 add_ensure_iseq(ret, iseq, 1);
04686 ADD_TRACE(ret, line, RUBY_EVENT_RETURN);
04687 ADD_INSN(ret, line, leave);
04688 ADD_ADJUST_RESTORE(ret, splabel);
04689
04690 if (!poped) {
04691 ADD_INSN(ret, line, putnil);
04692 }
04693 }
04694 else {
04695 ADD_INSN1(ret, line, throw, INT2FIX(0x01) );
04696 if (poped) {
04697 ADD_INSN(ret, line, pop);
04698 }
04699 }
04700 }
04701 }
04702 break;
04703 }
04704 case NODE_YIELD:{
04705 DECL_ANCHOR(args);
04706 VALUE argc;
04707 VALUE flag = 0;
04708
04709 INIT_ANCHOR(args);
04710 if (iseq->type == ISEQ_TYPE_TOP) {
04711 COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
04712 }
04713
04714 if (node->nd_head) {
04715 argc = setup_args(iseq, args, node->nd_head, &flag);
04716 }
04717 else {
04718 argc = INT2FIX(0);
04719 }
04720
04721 ADD_SEQ(ret, args);
04722 ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), 0, flag));
04723
04724 if (poped) {
04725 ADD_INSN(ret, line, pop);
04726 }
04727 break;
04728 }
04729 case NODE_LVAR:{
04730 if (!poped) {
04731 ID id = node->nd_vid;
04732 int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
04733
04734 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
04735 ADD_INSN2(ret, line, getlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
04736 }
04737 break;
04738 }
04739 case NODE_DVAR:{
04740 int lv, idx, ls;
04741 debugi("nd_vid", node->nd_vid);
04742 if (!poped) {
04743 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
04744 if (idx < 0) {
04745 rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid));
04746 }
04747 ADD_INSN2(ret, line, getlocal, INT2FIX(ls - idx), INT2FIX(lv));
04748 }
04749 break;
04750 }
04751 case NODE_GVAR:{
04752 ADD_INSN1(ret, line, getglobal,
04753 ((VALUE)node->nd_entry | 1));
04754 if (poped) {
04755 ADD_INSN(ret, line, pop);
04756 }
04757 break;
04758 }
04759 case NODE_IVAR:{
04760 debugi("nd_vid", node->nd_vid);
04761 if (!poped) {
04762 ADD_INSN2(ret, line, getinstancevariable,
04763 ID2SYM(node->nd_vid), INT2FIX(iseq->is_size++));
04764 }
04765 break;
04766 }
04767 case NODE_CONST:{
04768 debugi("nd_vid", node->nd_vid);
04769
04770 if (iseq->compile_data->option->inline_const_cache) {
04771 LABEL *lend = NEW_LABEL(line);
04772 int ic_index = iseq->is_size++;
04773
04774 ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
04775 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
04776 ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
04777 ADD_LABEL(ret, lend);
04778 }
04779 else {
04780 ADD_INSN(ret, line, putnil);
04781 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
04782 }
04783
04784 if (poped) {
04785 ADD_INSN(ret, line, pop);
04786 }
04787 break;
04788 }
04789 case NODE_CVAR:{
04790 if (!poped) {
04791 ADD_INSN1(ret, line, getclassvariable,
04792 ID2SYM(node->nd_vid));
04793 }
04794 break;
04795 }
04796 case NODE_NTH_REF:{
04797 if (!poped) {
04798 ADD_INSN2(ret, line, getspecial, INT2FIX(1) ,
04799 INT2FIX(node->nd_nth << 1));
04800 }
04801 break;
04802 }
04803 case NODE_BACK_REF:{
04804 if (!poped) {
04805 ADD_INSN2(ret, line, getspecial, INT2FIX(1) ,
04806 INT2FIX(0x01 | (node->nd_nth << 1)));
04807 }
04808 break;
04809 }
04810 case NODE_MATCH:
04811 case NODE_MATCH2:
04812 case NODE_MATCH3:{
04813 DECL_ANCHOR(recv);
04814 DECL_ANCHOR(val);
04815
04816 INIT_ANCHOR(recv);
04817 INIT_ANCHOR(val);
04818 switch (nd_type(node)) {
04819 case NODE_MATCH:
04820 ADD_INSN1(recv, line, putobject, node->nd_lit);
04821 ADD_INSN2(val, line, getspecial, INT2FIX(0),
04822 INT2FIX(0));
04823 break;
04824 case NODE_MATCH2:
04825 COMPILE(recv, "receiver", node->nd_recv);
04826 COMPILE(val, "value", node->nd_value);
04827 break;
04828 case NODE_MATCH3:
04829 COMPILE(recv, "receiver", node->nd_value);
04830 COMPILE(val, "value", node->nd_recv);
04831 break;
04832 }
04833
04834 if (iseq->compile_data->option->specialized_instruction) {
04835
04836 if (recv->last == recv->anchor.next &&
04837 INSN_OF(recv->last) == BIN(putobject) &&
04838 nd_type(node) == NODE_MATCH2) {
04839 ADD_SEQ(ret, val);
04840 ADD_INSN1(ret, line, opt_regexpmatch1,
04841 OPERAND_AT(recv->last, 0));
04842 }
04843 else {
04844 ADD_SEQ(ret, recv);
04845 ADD_SEQ(ret, val);
04846 ADD_INSN1(ret, line, opt_regexpmatch2, new_callinfo(iseq, idEqTilde, 1, 0, 0));
04847 }
04848 }
04849 else {
04850 ADD_SEQ(ret, recv);
04851 ADD_SEQ(ret, val);
04852 ADD_SEND(ret, line, ID2SYM(idEqTilde), INT2FIX(1));
04853 }
04854
04855 if (poped) {
04856 ADD_INSN(ret, line, pop);
04857 }
04858 break;
04859 }
04860 case NODE_LIT:{
04861 debugp_param("lit", node->nd_lit);
04862 if (!poped) {
04863 ADD_INSN1(ret, line, putobject, node->nd_lit);
04864 }
04865 break;
04866 }
04867 case NODE_STR:{
04868 node->nd_lit = rb_fstring(node->nd_lit);
04869 debugp_param("nd_lit", node->nd_lit);
04870 if (!poped) {
04871 ADD_INSN1(ret, line, putstring, node->nd_lit);
04872 }
04873 break;
04874 }
04875 case NODE_DSTR:{
04876 compile_dstr(iseq, ret, node);
04877
04878 if (poped) {
04879 ADD_INSN(ret, line, pop);
04880 }
04881 break;
04882 }
04883 case NODE_XSTR:{
04884 node->nd_lit = rb_fstring(node->nd_lit);
04885 ADD_CALL_RECEIVER(ret, line);
04886 ADD_INSN1(ret, line, putobject, node->nd_lit);
04887 ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
04888
04889 if (poped) {
04890 ADD_INSN(ret, line, pop);
04891 }
04892 break;
04893 }
04894 case NODE_DXSTR:{
04895 ADD_CALL_RECEIVER(ret, line);
04896 compile_dstr(iseq, ret, node);
04897 ADD_CALL(ret, line, ID2SYM(idBackquote), INT2FIX(1));
04898
04899 if (poped) {
04900 ADD_INSN(ret, line, pop);
04901 }
04902 break;
04903 }
04904 case NODE_EVSTR:{
04905 COMPILE(ret, "nd_body", node->nd_body);
04906
04907 if (poped) {
04908 ADD_INSN(ret, line, pop);
04909 }
04910 else {
04911 ADD_INSN(ret, line, tostring);
04912 }
04913 break;
04914 }
04915 case NODE_DREGX:{
04916 compile_dregx(iseq, ret, node);
04917
04918 if (poped) {
04919 ADD_INSN(ret, line, pop);
04920 }
04921 break;
04922 }
04923 case NODE_DREGX_ONCE:{
04924 int ic_index = iseq->is_size++;
04925 NODE *dregx_node = NEW_NODE(NODE_DREGX, node->u1.value, node->u2.value, node->u3.value);
04926 NODE *block_node = NEW_NODE(NODE_SCOPE, 0, dregx_node, 0);
04927 VALUE block_iseq = NEW_CHILD_ISEQVAL(block_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
04928
04929 ADD_INSN2(ret, line, once, block_iseq, INT2FIX(ic_index));
04930
04931 if (poped) {
04932 ADD_INSN(ret, line, pop);
04933 }
04934 break;
04935 }
04936 case NODE_ARGSCAT:{
04937 if (poped) {
04938 COMPILE(ret, "argscat head", node->nd_head);
04939 ADD_INSN1(ret, line, splatarray, Qfalse);
04940 ADD_INSN(ret, line, pop);
04941 COMPILE(ret, "argscat body", node->nd_body);
04942 ADD_INSN1(ret, line, splatarray, Qfalse);
04943 ADD_INSN(ret, line, pop);
04944 }
04945 else {
04946 COMPILE(ret, "argscat head", node->nd_head);
04947 COMPILE(ret, "argscat body", node->nd_body);
04948 ADD_INSN(ret, line, concatarray);
04949 }
04950 break;
04951 }
04952 case NODE_ARGSPUSH:{
04953 if (poped) {
04954 COMPILE(ret, "arsgpush head", node->nd_head);
04955 ADD_INSN1(ret, line, splatarray, Qfalse);
04956 ADD_INSN(ret, line, pop);
04957 COMPILE_(ret, "argspush body", node->nd_body, poped);
04958 }
04959 else {
04960 COMPILE(ret, "arsgpush head", node->nd_head);
04961 COMPILE_(ret, "argspush body", node->nd_body, poped);
04962 ADD_INSN1(ret, line, newarray, INT2FIX(1));
04963 ADD_INSN(ret, line, concatarray);
04964 }
04965 break;
04966 }
04967 case NODE_SPLAT:{
04968 COMPILE(ret, "splat", node->nd_head);
04969 ADD_INSN1(ret, line, splatarray, Qtrue);
04970
04971 if (poped) {
04972 ADD_INSN(ret, line, pop);
04973 }
04974 break;
04975 }
04976 case NODE_DEFN:{
04977 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
04978 rb_id2str(node->nd_mid),
04979 ISEQ_TYPE_METHOD, line);
04980
04981 debugp_param("defn/iseq", iseqval);
04982
04983 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
04984 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
04985 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
04986 ADD_INSN1(ret, line, putiseq, iseqval);
04987 ADD_SEND (ret, line, ID2SYM(id_core_define_method), INT2FIX(3));
04988
04989 if (poped) {
04990 ADD_INSN(ret, line, pop);
04991 }
04992
04993 debugp_param("defn", iseqval);
04994 break;
04995 }
04996 case NODE_DEFS:{
04997 VALUE iseqval = NEW_ISEQVAL(node->nd_defn,
04998 rb_id2str(node->nd_mid),
04999 ISEQ_TYPE_METHOD, line);
05000
05001 debugp_param("defs/iseq", iseqval);
05002
05003 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05004 COMPILE(ret, "defs: recv", node->nd_recv);
05005 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
05006 ADD_INSN1(ret, line, putiseq, iseqval);
05007 ADD_SEND (ret, line, ID2SYM(id_core_define_singleton_method), INT2FIX(3));
05008
05009 if (poped) {
05010 ADD_INSN(ret, line, pop);
05011 }
05012 break;
05013 }
05014 case NODE_ALIAS:{
05015 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05016 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
05017 COMPILE(ret, "alias arg1", node->u1.node);
05018 COMPILE(ret, "alias arg2", node->u2.node);
05019 ADD_SEND(ret, line, ID2SYM(id_core_set_method_alias), INT2FIX(3));
05020
05021 if (poped) {
05022 ADD_INSN(ret, line, pop);
05023 }
05024 break;
05025 }
05026 case NODE_VALIAS:{
05027 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05028 ADD_INSN1(ret, line, putobject, ID2SYM(node->u1.id));
05029 ADD_INSN1(ret, line, putobject, ID2SYM(node->u2.id));
05030 ADD_SEND(ret, line, ID2SYM(id_core_set_variable_alias), INT2FIX(2));
05031
05032 if (poped) {
05033 ADD_INSN(ret, line, pop);
05034 }
05035 break;
05036 }
05037 case NODE_UNDEF:{
05038 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05039 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
05040 COMPILE(ret, "undef arg", node->u2.node);
05041 ADD_SEND(ret, line, ID2SYM(id_core_undef_method), INT2FIX(2));
05042
05043 if (poped) {
05044 ADD_INSN(ret, line, pop);
05045 }
05046 break;
05047 }
05048 case NODE_CLASS:{
05049 VALUE iseqval =
05050 NEW_CHILD_ISEQVAL(
05051 node->nd_body,
05052 rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
05053 ISEQ_TYPE_CLASS, line);
05054 VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
05055 int flags = VM_DEFINECLASS_TYPE_CLASS;
05056 if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
05057 if (node->nd_super) flags |= VM_DEFINECLASS_FLAG_HAS_SUPERCLASS;
05058 COMPILE(ret, "super", node->nd_super);
05059 ADD_INSN3(ret, line, defineclass,
05060 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
05061
05062 if (poped) {
05063 ADD_INSN(ret, line, pop);
05064 }
05065 break;
05066 }
05067 case NODE_MODULE:{
05068 VALUE iseqval = NEW_CHILD_ISEQVAL(
05069 node->nd_body,
05070 rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
05071 ISEQ_TYPE_CLASS, line);
05072
05073 VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
05074 int flags = VM_DEFINECLASS_TYPE_MODULE;
05075 if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
05076 ADD_INSN (ret, line, putnil);
05077 ADD_INSN3(ret, line, defineclass,
05078 ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
05079 if (poped) {
05080 ADD_INSN(ret, line, pop);
05081 }
05082 break;
05083 }
05084 case NODE_SCLASS:{
05085 ID singletonclass;
05086 VALUE iseqval =
05087 NEW_ISEQVAL(node->nd_body, rb_str_new2("singleton class"),
05088 ISEQ_TYPE_CLASS, line);
05089
05090 COMPILE(ret, "sclass#recv", node->nd_recv);
05091 ADD_INSN (ret, line, putnil);
05092 CONST_ID(singletonclass, "singletonclass");
05093 ADD_INSN3(ret, line, defineclass,
05094 ID2SYM(singletonclass), iseqval,
05095 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
05096
05097 if (poped) {
05098 ADD_INSN(ret, line, pop);
05099 }
05100 break;
05101 }
05102 case NODE_COLON2:{
05103 if (rb_is_const_id(node->nd_mid)) {
05104
05105 LABEL *lend = NEW_LABEL(line);
05106 int ic_index = iseq->is_size++;
05107
05108 DECL_ANCHOR(pref);
05109 DECL_ANCHOR(body);
05110
05111 INIT_ANCHOR(pref);
05112 INIT_ANCHOR(body);
05113 compile_colon2(iseq, node, pref, body);
05114 if (LIST_SIZE_ZERO(pref)) {
05115 if (iseq->compile_data->option->inline_const_cache) {
05116 ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
05117 }
05118 else {
05119 ADD_INSN(ret, line, putnil);
05120 }
05121
05122 ADD_SEQ(ret, body);
05123
05124 if (iseq->compile_data->option->inline_const_cache) {
05125 ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
05126 ADD_LABEL(ret, lend);
05127 }
05128 }
05129 else {
05130 ADD_SEQ(ret, pref);
05131 ADD_SEQ(ret, body);
05132 }
05133 }
05134 else {
05135
05136 ADD_CALL_RECEIVER(ret, line);
05137 COMPILE(ret, "colon2#nd_head", node->nd_head);
05138 ADD_CALL(ret, line, ID2SYM(node->nd_mid),
05139 INT2FIX(1));
05140 }
05141 if (poped) {
05142 ADD_INSN(ret, line, pop);
05143 }
05144 break;
05145 }
05146 case NODE_COLON3:{
05147 LABEL *lend = NEW_LABEL(line);
05148 int ic_index = iseq->is_size++;
05149
05150 debugi("colon3#nd_mid", node->nd_mid);
05151
05152
05153 if (iseq->compile_data->option->inline_const_cache) {
05154 ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
05155 ADD_INSN(ret, line, pop);
05156 }
05157
05158 ADD_INSN1(ret, line, putobject, rb_cObject);
05159 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
05160
05161 if (iseq->compile_data->option->inline_const_cache) {
05162 ADD_INSN1(ret, line, setinlinecache, INT2FIX(ic_index));
05163 ADD_LABEL(ret, lend);
05164 }
05165
05166 if (poped) {
05167 ADD_INSN(ret, line, pop);
05168 }
05169 break;
05170 }
05171 case NODE_DOT2:
05172 case NODE_DOT3:{
05173 VALUE flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1);
05174 COMPILE(ret, "min", (NODE *) node->nd_beg);
05175 COMPILE(ret, "max", (NODE *) node->nd_end);
05176 if (poped) {
05177 ADD_INSN(ret, line, pop);
05178 ADD_INSN(ret, line, pop);
05179 }
05180 else {
05181 ADD_INSN1(ret, line, newrange, flag);
05182 }
05183 break;
05184 }
05185 case NODE_FLIP2:
05186 case NODE_FLIP3:{
05187 LABEL *lend = NEW_LABEL(line);
05188 LABEL *lfin = NEW_LABEL(line);
05189 LABEL *ltrue = NEW_LABEL(line);
05190 rb_iseq_t *local_iseq = iseq->local_iseq;
05191 rb_num_t cnt;
05192 VALUE key;
05193
05194 cnt = local_iseq->flip_cnt++ + DEFAULT_SPECIAL_VAR_COUNT;
05195 key = INT2FIX(cnt);
05196
05197 ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
05198 ADD_INSNL(ret, line, branchif, lend);
05199
05200
05201 COMPILE(ret, "flip2 beg", node->nd_beg);
05202 ADD_INSN(ret, line, dup);
05203 ADD_INSNL(ret, line, branchunless, lfin);
05204 if (nd_type(node) == NODE_FLIP3) {
05205 ADD_INSN(ret, line, dup);
05206 ADD_INSN1(ret, line, setspecial, key);
05207 ADD_INSNL(ret, line, jump, lfin);
05208 }
05209 else {
05210 ADD_INSN1(ret, line, setspecial, key);
05211 }
05212
05213
05214 ADD_LABEL(ret, lend);
05215 COMPILE(ret, "flip2 end", node->nd_end);
05216 ADD_INSNL(ret, line, branchunless, ltrue);
05217 ADD_INSN1(ret, line, putobject, Qfalse);
05218 ADD_INSN1(ret, line, setspecial, key);
05219
05220 ADD_LABEL(ret, ltrue);
05221 ADD_INSN1(ret, line, putobject, Qtrue);
05222
05223 ADD_LABEL(ret, lfin);
05224 break;
05225 }
05226 case NODE_SELF:{
05227 if (!poped) {
05228 ADD_INSN(ret, line, putself);
05229 }
05230 break;
05231 }
05232 case NODE_NIL:{
05233 if (!poped) {
05234 ADD_INSN(ret, line, putnil);
05235 }
05236 break;
05237 }
05238 case NODE_TRUE:{
05239 if (!poped) {
05240 ADD_INSN1(ret, line, putobject, Qtrue);
05241 }
05242 break;
05243 }
05244 case NODE_FALSE:{
05245 if (!poped) {
05246 ADD_INSN1(ret, line, putobject, Qfalse);
05247 }
05248 break;
05249 }
05250 case NODE_ERRINFO:{
05251 if (!poped) {
05252 if (iseq->type == ISEQ_TYPE_RESCUE) {
05253 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(0));
05254 }
05255 else {
05256 rb_iseq_t *ip = iseq;
05257 int level = 0;
05258 while (ip) {
05259 if (ip->type == ISEQ_TYPE_RESCUE) {
05260 break;
05261 }
05262 ip = ip->parent_iseq;
05263 level++;
05264 }
05265 if (ip) {
05266 ADD_INSN2(ret, line, getlocal, INT2FIX(2), INT2FIX(level));
05267 }
05268 else {
05269 ADD_INSN(ret, line, putnil);
05270 }
05271 }
05272 }
05273 break;
05274 }
05275 case NODE_DEFINED:{
05276 if (poped) break;
05277 if (!node->nd_head) {
05278 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
05279 ADD_INSN1(ret, nd_line(node), putobject, str);
05280 }
05281 else {
05282 LABEL *lfinish[2];
05283 lfinish[0] = NEW_LABEL(line);
05284 lfinish[1] = 0;
05285 ADD_INSN(ret, line, putnil);
05286 defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
05287 ADD_INSN(ret, line, swap);
05288 ADD_INSN(ret, line, pop);
05289 if (lfinish[1]) {
05290 ADD_LABEL(ret, lfinish[1]);
05291 }
05292 ADD_LABEL(ret, lfinish[0]);
05293 }
05294 break;
05295 }
05296 case NODE_POSTEXE:{
05297
05298
05299
05300 int is_index = iseq->is_size++;
05301 VALUE once_iseq = NEW_CHILD_ISEQVAL(
05302 NEW_IFUNC(build_postexe_iseq, node->nd_body),
05303 make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
05304
05305 ADD_INSN2(ret, line, once, once_iseq, INT2FIX(is_index));
05306
05307 if (poped) {
05308 ADD_INSN(ret, line, pop);
05309 }
05310 break;
05311 }
05312 case NODE_KW_ARG:{
05313 LABEL *default_label = NEW_LABEL(line);
05314 LABEL *end_label = 0;
05315 int idx, lv, ls;
05316 ID id = node->nd_body->nd_vid;
05317
05318 ADD_INSN(ret, line, dup);
05319 ADD_INSN1(ret, line, putobject, ID2SYM(id));
05320 ADD_SEND(ret, line, ID2SYM(rb_intern("key?")), INT2FIX(1));
05321 ADD_INSNL(ret, line, branchunless, default_label);
05322 ADD_INSN(ret, line, dup);
05323 ADD_INSN1(ret, line, putobject, ID2SYM(id));
05324 ADD_SEND(ret, line, ID2SYM(rb_intern("delete")), INT2FIX(1));
05325 switch (nd_type(node->nd_body)) {
05326 case NODE_LASGN:
05327 idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id);
05328 ADD_INSN2(ret, line, setlocal, INT2FIX(idx), INT2FIX(get_lvar_level(iseq)));
05329 break;
05330 case NODE_DASGN:
05331 case NODE_DASGN_CURR:
05332 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
05333 ADD_INSN2(ret, line, setlocal, INT2FIX(ls - idx), INT2FIX(lv));
05334 break;
05335 default:
05336 rb_bug("iseq_compile_each (NODE_KW_ARG): unknown node: %s", ruby_node_name(nd_type(node->nd_body)));
05337 }
05338 if (node->nd_body->nd_value != (NODE *)-1) {
05339 end_label = NEW_LABEL(nd_line(node));
05340 ADD_INSNL(ret, nd_line(node), jump, end_label);
05341 }
05342 ADD_LABEL(ret, default_label);
05343 if (node->nd_body->nd_value != (NODE *)-1) {
05344 COMPILE_POPED(ret, "keyword default argument", node->nd_body);
05345 ADD_LABEL(ret, end_label);
05346 }
05347 break;
05348 }
05349 case NODE_DSYM:{
05350 compile_dstr(iseq, ret, node);
05351 if (!poped) {
05352 ADD_SEND(ret, line, ID2SYM(idIntern), INT2FIX(0));
05353 }
05354 else {
05355 ADD_INSN(ret, line, pop);
05356 }
05357 break;
05358 }
05359 case NODE_ATTRASGN:{
05360 DECL_ANCHOR(recv);
05361 DECL_ANCHOR(args);
05362 VALUE flag = 0;
05363 VALUE argc;
05364
05365 INIT_ANCHOR(recv);
05366 INIT_ANCHOR(args);
05367 argc = setup_args(iseq, args, node->nd_args, &flag);
05368
05369 if (node->nd_recv == (NODE *) 1) {
05370 flag |= VM_CALL_FCALL;
05371 ADD_INSN(recv, line, putself);
05372 }
05373 else {
05374 COMPILE(recv, "recv", node->nd_recv);
05375 }
05376
05377 debugp_param("argc", argc);
05378 debugp_param("nd_mid", ID2SYM(node->nd_mid));
05379
05380 if (!poped) {
05381 ADD_INSN(ret, line, putnil);
05382 ADD_SEQ(ret, recv);
05383 ADD_SEQ(ret, args);
05384
05385 if (flag & VM_CALL_ARGS_BLOCKARG) {
05386 ADD_INSN1(ret, line, topn, INT2FIX(1));
05387 if (flag & VM_CALL_ARGS_SPLAT) {
05388 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
05389 ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
05390 }
05391 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
05392 ADD_INSN (ret, line, pop);
05393 }
05394 else if (flag & VM_CALL_ARGS_SPLAT) {
05395 ADD_INSN(ret, line, dup);
05396 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
05397 ADD_SEND(ret, line, ID2SYM(idAREF), INT2FIX(1));
05398 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
05399 ADD_INSN (ret, line, pop);
05400 }
05401 else {
05402 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
05403 }
05404 }
05405 else {
05406 ADD_SEQ(ret, recv);
05407 ADD_SEQ(ret, args);
05408 }
05409 ADD_SEND_R(ret, line, ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag));
05410 ADD_INSN(ret, line, pop);
05411
05412 break;
05413 }
05414 case NODE_PRELUDE:{
05415 COMPILE_POPED(ret, "prelude", node->nd_head);
05416 COMPILE_(ret, "body", node->nd_body, poped);
05417 break;
05418 }
05419 case NODE_LAMBDA:{
05420
05421 VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
05422 VALUE argc = INT2FIX(0);
05423 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
05424 ADD_CALL_WITH_BLOCK(ret, line, ID2SYM(idLambda), argc, block);
05425
05426 if (poped) {
05427 ADD_INSN(ret, line, pop);
05428 }
05429 break;
05430 }
05431 default:
05432 rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type));
05433 return COMPILE_NG;
05434 }
05435
05436
05437 if (saved_last_element && ret &&
05438 ret->last == saved_last_element &&
05439 ((INSN *)saved_last_element)->insn_id == BIN(trace)) {
05440 POP_ELEMENT(ret);
05441 }
05442
05443 debug_node_end();
05444 return COMPILE_OK;
05445 }
05446
05447
05448
05449
05450
05451 static int
05452 insn_data_length(INSN *iobj)
05453 {
05454 return insn_len(iobj->insn_id);
05455 }
05456
05457 static int
05458 calc_sp_depth(int depth, INSN *insn)
05459 {
05460 return insn_stack_increase(depth, insn->insn_id, insn->operands);
05461 }
05462
05463 static VALUE
05464 opobj_inspect(VALUE obj)
05465 {
05466 struct RBasic *r = (struct RBasic *) obj;
05467 if (!SPECIAL_CONST_P(r) && r->klass == 0) {
05468 switch (BUILTIN_TYPE(r)) {
05469 case T_STRING:
05470 obj = rb_str_new_cstr(RSTRING_PTR(obj));
05471 break;
05472 case T_ARRAY:
05473 obj = rb_ary_dup(obj);
05474 break;
05475 }
05476 }
05477 return rb_inspect(obj);
05478 }
05479
05480
05481
05482 static VALUE
05483 insn_data_to_s_detail(INSN *iobj)
05484 {
05485 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
05486
05487 if (iobj->operands) {
05488 const char *types = insn_op_types(iobj->insn_id);
05489 int j;
05490
05491 for (j = 0; types[j]; j++) {
05492 char type = types[j];
05493
05494 switch (type) {
05495 case TS_OFFSET:
05496 {
05497 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
05498 rb_str_catf(str, "<L%03d>", lobj->label_no);
05499 break;
05500 }
05501 break;
05502 case TS_ISEQ:
05503 {
05504 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
05505 VALUE val = Qnil;
05506 if (0 && iseq) {
05507 val = iseq->self;
05508 }
05509 rb_str_concat(str, opobj_inspect(val));
05510 }
05511 break;
05512 case TS_LINDEX:
05513 case TS_NUM:
05514 case TS_VALUE:
05515 {
05516 VALUE v = OPERAND_AT(iobj, j);
05517 rb_str_concat(str, opobj_inspect(v));
05518 break;
05519 }
05520 case TS_ID:
05521 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
05522 break;
05523 case TS_GENTRY:
05524 {
05525 struct rb_global_entry *entry = (struct rb_global_entry *)
05526 (OPERAND_AT(iobj, j) & (~1));
05527 rb_str_cat2(str, rb_id2name(entry->id));
05528 break;
05529 }
05530 case TS_IC:
05531 rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
05532 break;
05533 case TS_CALLINFO:
05534 {
05535 rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, j);
05536 rb_str_catf(str, "<callinfo:%s, %d>", ci->mid ? rb_id2name(ci->mid) : "", ci->orig_argc);
05537 break;
05538 }
05539 case TS_CDHASH:
05540 rb_str_cat2(str, "<ch>");
05541 break;
05542 default:{
05543 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
05544 }
05545 }
05546 if (types[j + 1]) {
05547 rb_str_cat2(str, ", ");
05548 }
05549 }
05550 }
05551 return str;
05552 }
05553
05554 static void
05555 dump_disasm_list(struct iseq_link_element *link)
05556 {
05557 int pos = 0;
05558 INSN *iobj;
05559 LABEL *lobj;
05560 VALUE str;
05561
05562 printf("-- raw disasm--------\n");
05563
05564 while (link) {
05565 switch (link->type) {
05566 case ISEQ_ELEMENT_INSN:
05567 {
05568 iobj = (INSN *)link;
05569 str = insn_data_to_s_detail(iobj);
05570 printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str), iobj->line_no);
05571 pos += insn_data_length(iobj);
05572 break;
05573 }
05574 case ISEQ_ELEMENT_LABEL:
05575 {
05576 lobj = (LABEL *)link;
05577 printf("<L%03d>\n", lobj->label_no);
05578 break;
05579 }
05580 case ISEQ_ELEMENT_NONE:
05581 {
05582 printf("[none]\n");
05583 break;
05584 }
05585 case ISEQ_ELEMENT_ADJUST:
05586 {
05587 ADJUST *adjust = (ADJUST *)link;
05588 printf("adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
05589 break;
05590 }
05591 default:
05592
05593 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
05594 }
05595 link = link->next;
05596 }
05597 printf("---------------------\n");
05598 }
05599
05600 const char *
05601 rb_insns_name(int i)
05602 {
05603 return insn_name_info[i];
05604 }
05605
05606 VALUE
05607 rb_insns_name_array(void)
05608 {
05609 VALUE ary = rb_ary_new();
05610 int i;
05611 for (i = 0; i < numberof(insn_name_info); i++) {
05612 rb_ary_push(ary, rb_fstring(rb_str_new2(insn_name_info[i])));
05613 }
05614 return rb_obj_freeze(ary);
05615 }
05616
05617 static LABEL *
05618 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
05619 {
05620 LABEL *label = 0;
05621 st_data_t tmp;
05622 obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym");
05623
05624 if (st_lookup(labels_table, obj, &tmp) == 0) {
05625 label = NEW_LABEL(0);
05626 st_insert(labels_table, obj, (st_data_t)label);
05627 }
05628 else {
05629 label = (LABEL *)tmp;
05630 }
05631 return label;
05632 }
05633
05634 static VALUE
05635 get_exception_sym2type(VALUE sym)
05636 {
05637 #undef rb_intern
05638 #define rb_intern(str) rb_intern_const(str)
05639 VALUE sym_inspect;
05640 static VALUE symRescue, symEnsure, symRetry;
05641 static VALUE symBreak, symRedo, symNext;
05642
05643 if (symRescue == 0) {
05644 symRescue = ID2SYM(rb_intern("rescue"));
05645 symEnsure = ID2SYM(rb_intern("ensure"));
05646 symRetry = ID2SYM(rb_intern("retry"));
05647 symBreak = ID2SYM(rb_intern("break"));
05648 symRedo = ID2SYM(rb_intern("redo"));
05649 symNext = ID2SYM(rb_intern("next"));
05650 }
05651
05652 if (sym == symRescue) return CATCH_TYPE_RESCUE;
05653 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
05654 if (sym == symRetry) return CATCH_TYPE_RETRY;
05655 if (sym == symBreak) return CATCH_TYPE_BREAK;
05656 if (sym == symRedo) return CATCH_TYPE_REDO;
05657 if (sym == symNext) return CATCH_TYPE_NEXT;
05658 sym_inspect = rb_inspect(sym);
05659 rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
05660 StringValuePtr(sym_inspect));
05661 return 0;
05662 }
05663
05664 static int
05665 iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
05666 VALUE exception)
05667 {
05668 int i;
05669
05670 for (i=0; i<RARRAY_LEN(exception); i++) {
05671 VALUE v, type, eiseqval;
05672 const VALUE *ptr;
05673 LABEL *lstart, *lend, *lcont;
05674 int sp;
05675
05676 RB_GC_GUARD(v) = rb_convert_type(RARRAY_AREF(exception, i), T_ARRAY,
05677 "Array", "to_ary");
05678 if (RARRAY_LEN(v) != 6) {
05679 rb_raise(rb_eSyntaxError, "wrong exception entry");
05680 }
05681 ptr = RARRAY_CONST_PTR(v);
05682 type = get_exception_sym2type(ptr[0]);
05683 if (ptr[1] == Qnil) {
05684 eiseqval = 0;
05685 }
05686 else {
05687 eiseqval = rb_iseq_load(ptr[1], iseq->self, Qnil);
05688 }
05689
05690 lstart = register_label(iseq, labels_table, ptr[2]);
05691 lend = register_label(iseq, labels_table, ptr[3]);
05692 lcont = register_label(iseq, labels_table, ptr[4]);
05693 sp = NUM2INT(ptr[5]);
05694
05695 (void)sp;
05696
05697 ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
05698 }
05699 return COMPILE_OK;
05700 }
05701
05702 static struct st_table *
05703 insn_make_insn_table(void)
05704 {
05705 struct st_table *table;
05706 int i;
05707 table = st_init_numtable();
05708
05709 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
05710 st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
05711 }
05712
05713 return table;
05714 }
05715
05716 static VALUE
05717 iseq_build_load_iseq(rb_iseq_t *iseq, VALUE op)
05718 {
05719 VALUE iseqval;
05720 if (RB_TYPE_P(op, T_ARRAY)) {
05721 iseqval = rb_iseq_load(op, iseq->self, Qnil);
05722 }
05723 else if (CLASS_OF(op) == rb_cISeq) {
05724 iseqval = op;
05725 }
05726 else {
05727 rb_raise(rb_eSyntaxError, "ISEQ is required");
05728 }
05729 iseq_add_mark_object(iseq, iseqval);
05730 return iseqval;
05731 }
05732
05733 static int
05734 iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
05735 VALUE body, struct st_table *labels_table)
05736 {
05737
05738 const VALUE *ptr = RARRAY_CONST_PTR(body);
05739 long i, len = RARRAY_LEN(body);
05740 int j;
05741 int line_no = 0;
05742
05743
05744
05745
05746 static struct st_table *insn_table;
05747
05748 if (insn_table == 0) {
05749 insn_table = insn_make_insn_table();
05750 }
05751
05752 for (i=0; i<len; i++) {
05753 VALUE obj = ptr[i];
05754
05755 if (SYMBOL_P(obj)) {
05756 LABEL *label = register_label(iseq, labels_table, obj);
05757 ADD_LABEL(anchor, label);
05758 }
05759 else if (FIXNUM_P(obj)) {
05760 line_no = NUM2INT(obj);
05761 }
05762 else if (RB_TYPE_P(obj, T_ARRAY)) {
05763 VALUE *argv = 0;
05764 int argc = RARRAY_LENINT(obj) - 1;
05765 st_data_t insn_id;
05766 VALUE insn;
05767
05768 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
05769 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
05770
05771 RB_GC_GUARD(insn) = rb_inspect(insn);
05772 rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
05773 "unknown instruction: %s", RSTRING_PTR(insn));
05774 }
05775
05776 if (argc != insn_len((VALUE)insn_id)-1) {
05777 rb_compile_error(RSTRING_PTR(iseq->location.path), line_no,
05778 "operand size mismatch");
05779 }
05780
05781 if (argc > 0) {
05782 argv = compile_data_alloc(iseq, sizeof(VALUE) * argc);
05783 for (j=0; j<argc; j++) {
05784 VALUE op = rb_ary_entry(obj, j+1);
05785 switch (insn_op_type((VALUE)insn_id, j)) {
05786 case TS_OFFSET: {
05787 LABEL *label = register_label(iseq, labels_table, op);
05788 argv[j] = (VALUE)label;
05789 break;
05790 }
05791 case TS_LINDEX:
05792 case TS_NUM:
05793 (void)NUM2INT(op);
05794 argv[j] = op;
05795 break;
05796 case TS_VALUE:
05797 argv[j] = op;
05798 iseq_add_mark_object(iseq, op);
05799 break;
05800 case TS_ISEQ:
05801 {
05802 if (op != Qnil) {
05803 argv[j] = iseq_build_load_iseq(iseq, op);
05804 }
05805 else {
05806 argv[j] = 0;
05807 }
05808 }
05809 break;
05810 case TS_GENTRY:
05811 op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym");
05812 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
05813 break;
05814 case TS_IC:
05815 argv[j] = op;
05816 if (NUM2INT(op) >= iseq->is_size) {
05817 iseq->is_size = NUM2INT(op) + 1;
05818 }
05819 break;
05820 case TS_CALLINFO:
05821 {
05822 ID mid = 0;
05823 int orig_argc = 0;
05824 VALUE block = 0;
05825 unsigned long flag = 0;
05826
05827 if (!NIL_P(op)) {
05828 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
05829 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
05830 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
05831 VALUE vblock = rb_hash_aref(op, ID2SYM(rb_intern("blockptr")));
05832
05833 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
05834 if (!NIL_P(vflag)) flag = NUM2ULONG(vflag);
05835 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
05836 if (!NIL_P(vblock)) block = iseq_build_load_iseq(iseq, vblock);
05837 }
05838 argv[j] = (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag);
05839 }
05840 break;
05841 case TS_ID:
05842 argv[j] = rb_convert_type(op, T_SYMBOL,
05843 "Symbol", "to_sym");
05844 break;
05845 case TS_CDHASH:
05846 {
05847 int i;
05848 op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
05849 op = rb_ary_dup(op);
05850 for (i=0; i<RARRAY_LEN(op); i+=2) {
05851 VALUE sym = rb_ary_entry(op, i+1);
05852 LABEL *label =
05853 register_label(iseq, labels_table, sym);
05854 rb_ary_store(op, i+1, (VALUE)label | 1);
05855 }
05856 argv[j] = op;
05857 iseq_add_mark_object_compile_time(iseq, op);
05858 }
05859 break;
05860 default:
05861 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
05862 }
05863 }
05864 }
05865 ADD_ELEM(anchor,
05866 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
05867 (enum ruby_vminsn_type)insn_id, argc, argv));
05868 }
05869 else {
05870 rb_raise(rb_eTypeError, "unexpected object for instruction");
05871 }
05872 }
05873 validate_labels(iseq, labels_table);
05874 st_free_table(labels_table);
05875 iseq_setup(iseq, anchor);
05876 return COMPILE_OK;
05877 }
05878
05879 #define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
05880 #define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
05881 #define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
05882 static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
05883
05884 VALUE
05885 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
05886 VALUE exception, VALUE body)
05887 {
05888 int i;
05889 ID *tbl;
05890 struct st_table *labels_table = st_init_numtable();
05891 DECL_ANCHOR(anchor);
05892 INIT_ANCHOR(anchor);
05893
05894 iseq->local_table_size = RARRAY_LENINT(locals);
05895 iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
05896 iseq->local_size = iseq->local_table_size + 1;
05897
05898 for (i=0; i<RARRAY_LEN(locals); i++) {
05899 VALUE lv = RARRAY_AREF(locals, i);
05900 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
05901 }
05902
05903
05904 if (FIXNUM_P(args)) {
05905 iseq->arg_size = iseq->argc = FIX2INT(args);
05906 iseq->arg_simple = 1;
05907 }
05908 else {
05909 int i = 0;
05910 VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
05911 VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
05912 VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++));
05913 VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
05914 VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
05915 VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
05916 VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
05917
05918 iseq->argc = FIX2INT(argc);
05919 iseq->arg_rest = FIX2INT(arg_rest);
05920 iseq->arg_post_len = FIX2INT(arg_post_len);
05921 iseq->arg_post_start = FIX2INT(arg_post_start);
05922 iseq->arg_block = FIX2INT(arg_block);
05923 iseq->arg_opts = RARRAY_LENINT(arg_opt_labels);
05924 iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
05925
05926 if (iseq->arg_block != -1) {
05927 iseq->arg_size = iseq->arg_block + 1;
05928 }
05929 else if (iseq->arg_post_len) {
05930 iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len;
05931 }
05932 else if (iseq->arg_rest != -1) {
05933 iseq->arg_size = iseq->arg_rest + 1;
05934 }
05935 else {
05936 iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
05937 }
05938
05939 for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
05940 iseq->arg_opt_table[i] =
05941 (VALUE)register_label(iseq, labels_table,
05942 rb_ary_entry(arg_opt_labels, i));
05943 }
05944
05945 iseq->arg_simple = NUM2INT(arg_simple);
05946 }
05947
05948
05949 iseq_build_from_ary_exception(iseq, labels_table, exception);
05950
05951
05952 iseq_build_from_ary_body(iseq, anchor, body, labels_table);
05953 return iseq->self;
05954 }
05955
05956
05957
05958 int
05959 rb_dvar_defined(ID id)
05960 {
05961 rb_thread_t *th = GET_THREAD();
05962 rb_iseq_t *iseq;
05963 if (th->base_block && (iseq = th->base_block->iseq)) {
05964 while (iseq->type == ISEQ_TYPE_BLOCK ||
05965 iseq->type == ISEQ_TYPE_RESCUE ||
05966 iseq->type == ISEQ_TYPE_ENSURE ||
05967 iseq->type == ISEQ_TYPE_EVAL ||
05968 iseq->type == ISEQ_TYPE_MAIN
05969 ) {
05970 int i;
05971
05972 for (i = 0; i < iseq->local_table_size; i++) {
05973 if (iseq->local_table[i] == id) {
05974 return 1;
05975 }
05976 }
05977 iseq = iseq->parent_iseq;
05978 }
05979 }
05980 return 0;
05981 }
05982
05983 int
05984 rb_local_defined(ID id)
05985 {
05986 rb_thread_t *th = GET_THREAD();
05987 rb_iseq_t *iseq;
05988
05989 if (th->base_block && th->base_block->iseq) {
05990 int i;
05991 iseq = th->base_block->iseq->local_iseq;
05992
05993 for (i=0; i<iseq->local_table_size; i++) {
05994 if (iseq->local_table[i] == id) {
05995 return 1;
05996 }
05997 }
05998 }
05999 return 0;
06000 }
06001
06002 int
06003 rb_parse_in_eval(void)
06004 {
06005 return GET_THREAD()->parse_in_eval > 0;
06006 }
06007
06008 int
06009 rb_parse_in_main(void)
06010 {
06011 return GET_THREAD()->parse_in_eval < 0;
06012 }
06013