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