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