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