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