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