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