Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /********************************************************************** 00002 00003 vm_insnhelper.c - instruction helper functions. 00004 00005 $Author: nagachika $ 00006 00007 Copyright (C) 2007 Koichi Sasada 00008 00009 **********************************************************************/ 00010 00011 /* finish iseq array */ 00012 #include "insns.inc" 00013 #include <math.h> 00014 #include "constant.h" 00015 #include "internal.h" 00016 #include "probes.h" 00017 #include "probes_helper.h" 00018 00019 /* control stack frame */ 00020 00021 #ifndef INLINE 00022 #define INLINE inline 00023 #endif 00024 00025 static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp); 00026 00027 static void 00028 vm_stackoverflow(void) 00029 { 00030 rb_exc_raise(sysstack_error); 00031 } 00032 00033 static inline rb_control_frame_t * 00034 vm_push_frame(rb_thread_t *th, 00035 const rb_iseq_t *iseq, 00036 VALUE type, 00037 VALUE self, 00038 VALUE klass, 00039 VALUE specval, 00040 const VALUE *pc, 00041 VALUE *sp, 00042 int local_size, 00043 const rb_method_entry_t *me) 00044 { 00045 rb_control_frame_t *const cfp = th->cfp - 1; 00046 int i; 00047 00048 /* check stack overflow */ 00049 if ((void *)(sp + local_size) >= (void *)cfp) { 00050 vm_stackoverflow(); 00051 } 00052 th->cfp = cfp; 00053 00054 /* setup vm value stack */ 00055 00056 /* initialize local variables */ 00057 for (i=0; i < local_size; i++) { 00058 *sp++ = Qnil; 00059 } 00060 00061 /* set special val */ 00062 *sp = specval; 00063 00064 /* setup vm control frame stack */ 00065 00066 cfp->pc = (VALUE *)pc; 00067 cfp->sp = sp + 1; 00068 #if VM_DEBUG_BP_CHECK 00069 cfp->bp_check = sp + 1; 00070 #endif 00071 cfp->ep = sp; 00072 cfp->iseq = (rb_iseq_t *) iseq; 00073 cfp->flag = type; 00074 cfp->self = self; 00075 cfp->block_iseq = 0; 00076 cfp->proc = 0; 00077 cfp->me = me; 00078 if (klass) { 00079 cfp->klass = klass; 00080 } 00081 else { 00082 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00083 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) { 00084 cfp->klass = Qnil; 00085 } 00086 else { 00087 cfp->klass = prev_cfp->klass; 00088 } 00089 } 00090 00091 if (VMDEBUG == 2) { 00092 SDR(); 00093 } 00094 00095 return cfp; 00096 } 00097 00098 static inline void 00099 vm_pop_frame(rb_thread_t *th) 00100 { 00101 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); 00102 00103 if (VMDEBUG == 2) { 00104 SDR(); 00105 } 00106 } 00107 00108 /* method dispatch */ 00109 static inline VALUE 00110 rb_arg_error_new(int argc, int min, int max) 00111 { 00112 VALUE err_mess = 0; 00113 if (min == max) { 00114 err_mess = rb_sprintf("wrong number of arguments (%d for %d)", argc, min); 00115 } 00116 else if (max == UNLIMITED_ARGUMENTS) { 00117 err_mess = rb_sprintf("wrong number of arguments (%d for %d+)", argc, min); 00118 } 00119 else { 00120 err_mess = rb_sprintf("wrong number of arguments (%d for %d..%d)", argc, min, max); 00121 } 00122 return rb_exc_new3(rb_eArgError, err_mess); 00123 } 00124 00125 NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc)); 00126 static void 00127 argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc) 00128 { 00129 VALUE exc = rb_arg_error_new(miss_argc, min_argc, max_argc); 00130 VALUE bt = rb_make_backtrace(); 00131 VALUE err_line = 0; 00132 00133 if (iseq) { 00134 int line_no = rb_iseq_first_lineno(iseq); 00135 00136 err_line = rb_sprintf("%s:%d:in `%s'", 00137 RSTRING_PTR(iseq->location.path), 00138 line_no, RSTRING_PTR(iseq->location.label)); 00139 rb_funcall(bt, rb_intern("unshift"), 1, err_line); 00140 } 00141 00142 rb_funcall(exc, rb_intern("set_backtrace"), 1, bt); 00143 rb_exc_raise(exc); 00144 } 00145 00146 NORETURN(static void unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash)); 00147 static void 00148 unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash) 00149 { 00150 VALUE sep = rb_usascii_str_new2(", "), keys; 00151 const char *msg; 00152 int i; 00153 for (i = 0; i < iseq->arg_keywords; i++) { 00154 rb_hash_delete(hash, ID2SYM(iseq->arg_keyword_table[i])); 00155 } 00156 keys = rb_funcall(hash, rb_intern("keys"), 0, 0); 00157 if (!RB_TYPE_P(keys, T_ARRAY)) rb_raise(rb_eArgError, "unknown keyword"); 00158 msg = RARRAY_LEN(keys) == 1 ? "" : "s"; 00159 keys = rb_funcall(keys, rb_intern("join"), 1, sep); 00160 rb_raise(rb_eArgError, "unknown keyword%s: %"PRIsVALUE, msg, keys); 00161 } 00162 00163 void 00164 rb_error_arity(int argc, int min, int max) 00165 { 00166 rb_exc_raise(rb_arg_error_new(argc, min, max)); 00167 } 00168 00169 /* svar */ 00170 00171 static inline NODE * 00172 lep_svar_place(rb_thread_t *th, VALUE *lep) 00173 { 00174 VALUE *svar; 00175 00176 if (lep && th->root_lep != lep) { 00177 svar = &lep[-1]; 00178 } 00179 else { 00180 svar = &th->root_svar; 00181 } 00182 if (NIL_P(*svar)) { 00183 *svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil); 00184 } 00185 return (NODE *)*svar; 00186 } 00187 00188 static VALUE 00189 lep_svar_get(rb_thread_t *th, VALUE *lep, rb_num_t key) 00190 { 00191 NODE *svar = lep_svar_place(th, lep); 00192 00193 switch (key) { 00194 case 0: 00195 return svar->u1.value; 00196 case 1: 00197 return svar->u2.value; 00198 default: { 00199 const VALUE ary = svar->u3.value; 00200 00201 if (NIL_P(ary)) { 00202 return Qnil; 00203 } 00204 else { 00205 return rb_ary_entry(ary, key - DEFAULT_SPECIAL_VAR_COUNT); 00206 } 00207 } 00208 } 00209 } 00210 00211 static void 00212 lep_svar_set(rb_thread_t *th, VALUE *lep, rb_num_t key, VALUE val) 00213 { 00214 NODE *svar = lep_svar_place(th, lep); 00215 00216 switch (key) { 00217 case 0: 00218 svar->u1.value = val; 00219 return; 00220 case 1: 00221 svar->u2.value = val; 00222 return; 00223 default: { 00224 VALUE ary = svar->u3.value; 00225 00226 if (NIL_P(ary)) { 00227 svar->u3.value = ary = rb_ary_new(); 00228 } 00229 rb_ary_store(ary, key - DEFAULT_SPECIAL_VAR_COUNT, val); 00230 } 00231 } 00232 } 00233 00234 static inline VALUE 00235 vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type) 00236 { 00237 VALUE val; 00238 00239 if (type == 0) { 00240 val = lep_svar_get(th, lep, key); 00241 } 00242 else { 00243 VALUE backref = lep_svar_get(th, lep, 1); 00244 00245 if (type & 0x01) { 00246 switch (type >> 1) { 00247 case '&': 00248 val = rb_reg_last_match(backref); 00249 break; 00250 case '`': 00251 val = rb_reg_match_pre(backref); 00252 break; 00253 case '\'': 00254 val = rb_reg_match_post(backref); 00255 break; 00256 case '+': 00257 val = rb_reg_match_last(backref); 00258 break; 00259 default: 00260 rb_bug("unexpected back-ref"); 00261 } 00262 } 00263 else { 00264 val = rb_reg_nth_match((int)(type >> 1), backref); 00265 } 00266 } 00267 return val; 00268 } 00269 00270 static NODE * 00271 vm_get_cref0(const rb_iseq_t *iseq, const VALUE *ep) 00272 { 00273 while (1) { 00274 if (VM_EP_LEP_P(ep)) { 00275 if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL; 00276 return iseq->cref_stack; 00277 } 00278 else if (ep[-1] != Qnil) { 00279 return (NODE *)ep[-1]; 00280 } 00281 ep = VM_EP_PREV_EP(ep); 00282 } 00283 } 00284 00285 NODE * 00286 rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *ep) 00287 { 00288 NODE *cref = vm_get_cref0(iseq, ep); 00289 00290 if (cref == 0) { 00291 rb_bug("rb_vm_get_cref: unreachable"); 00292 } 00293 return cref; 00294 } 00295 00296 static NODE * 00297 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) 00298 { 00299 rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp); 00300 NODE *cref = NEW_CREF(klass); 00301 cref->nd_refinements = Qnil; 00302 cref->nd_visi = noex; 00303 00304 if (blockptr) { 00305 cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->ep); 00306 } 00307 else if (cfp) { 00308 cref->nd_next = vm_get_cref0(cfp->iseq, cfp->ep); 00309 } 00310 /* TODO: why cref->nd_next is 1? */ 00311 if (cref->nd_next && cref->nd_next != (void *) 1 && 00312 !NIL_P(cref->nd_next->nd_refinements)) { 00313 COPY_CREF_OMOD(cref, cref->nd_next); 00314 } 00315 00316 return cref; 00317 } 00318 00319 static inline VALUE 00320 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep) 00321 { 00322 NODE *cref = rb_vm_get_cref(iseq, ep); 00323 VALUE klass = Qundef; 00324 00325 while (cref) { 00326 if ((klass = cref->nd_clss) != 0) { 00327 break; 00328 } 00329 cref = cref->nd_next; 00330 } 00331 00332 return klass; 00333 } 00334 00335 static inline VALUE 00336 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *ep) 00337 { 00338 NODE *cref = rb_vm_get_cref(iseq, ep); 00339 VALUE klass = Qundef; 00340 00341 while (cref) { 00342 if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) && 00343 (klass = cref->nd_clss) != 0) { 00344 break; 00345 } 00346 cref = cref->nd_next; 00347 } 00348 00349 return klass; 00350 } 00351 00352 static inline void 00353 vm_check_if_namespace(VALUE klass) 00354 { 00355 VALUE str; 00356 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE)) { 00357 str = rb_inspect(klass); 00358 rb_raise(rb_eTypeError, "%s is not a class/module", 00359 StringValuePtr(str)); 00360 } 00361 } 00362 00363 static inline VALUE 00364 vm_get_iclass(rb_control_frame_t *cfp, VALUE klass) 00365 { 00366 if (RB_TYPE_P(klass, T_MODULE) && 00367 FL_TEST(klass, RMODULE_IS_OVERLAID) && 00368 RB_TYPE_P(cfp->klass, T_ICLASS) && 00369 RBASIC(cfp->klass)->klass == klass) { 00370 return cfp->klass; 00371 } 00372 else { 00373 return klass; 00374 } 00375 } 00376 00377 static inline VALUE 00378 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, 00379 VALUE orig_klass, ID id, int is_defined) 00380 { 00381 VALUE val; 00382 00383 if (orig_klass == Qnil) { 00384 /* in current lexical scope */ 00385 const NODE *root_cref = rb_vm_get_cref(iseq, th->cfp->ep); 00386 const NODE *cref; 00387 VALUE klass = orig_klass; 00388 00389 while (root_cref && root_cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) { 00390 root_cref = root_cref->nd_next; 00391 } 00392 cref = root_cref; 00393 while (cref && cref->nd_next) { 00394 if (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) { 00395 klass = Qnil; 00396 } 00397 else { 00398 klass = cref->nd_clss; 00399 } 00400 cref = cref->nd_next; 00401 00402 if (!NIL_P(klass)) { 00403 VALUE av, am = 0; 00404 st_data_t data; 00405 search_continue: 00406 if (RCLASS_CONST_TBL(klass) && 00407 st_lookup(RCLASS_CONST_TBL(klass), id, &data)) { 00408 val = ((rb_const_entry_t*)data)->value; 00409 if (val == Qundef) { 00410 if (am == klass) break; 00411 am = klass; 00412 if (is_defined) return 1; 00413 if (rb_autoloading_value(klass, id, &av)) return av; 00414 rb_autoload_load(klass, id); 00415 goto search_continue; 00416 } 00417 else { 00418 if (is_defined) { 00419 return 1; 00420 } 00421 else { 00422 return val; 00423 } 00424 } 00425 } 00426 } 00427 } 00428 00429 /* search self */ 00430 if (root_cref && !NIL_P(root_cref->nd_clss)) { 00431 klass = vm_get_iclass(th->cfp, root_cref->nd_clss); 00432 } 00433 else { 00434 klass = CLASS_OF(th->cfp->self); 00435 } 00436 00437 if (is_defined) { 00438 return rb_const_defined(klass, id); 00439 } 00440 else { 00441 return rb_const_get(klass, id); 00442 } 00443 } 00444 else { 00445 vm_check_if_namespace(orig_klass); 00446 if (is_defined) { 00447 return rb_public_const_defined_from(orig_klass, id); 00448 } 00449 else { 00450 return rb_public_const_get_from(orig_klass, id); 00451 } 00452 } 00453 } 00454 00455 static inline VALUE 00456 vm_get_cvar_base(NODE *cref, rb_control_frame_t *cfp) 00457 { 00458 VALUE klass; 00459 00460 if (!cref) { 00461 rb_bug("vm_get_cvar_base: no cref"); 00462 } 00463 00464 while (cref->nd_next && 00465 (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) || 00466 (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) { 00467 cref = cref->nd_next; 00468 } 00469 if (!cref->nd_next) { 00470 rb_warn("class variable access from toplevel"); 00471 } 00472 00473 klass = vm_get_iclass(cfp, cref->nd_clss); 00474 00475 if (NIL_P(klass)) { 00476 rb_raise(rb_eTypeError, "no class variables available"); 00477 } 00478 return klass; 00479 } 00480 00481 static VALUE 00482 vm_search_const_defined_class(const VALUE cbase, ID id) 00483 { 00484 if (rb_const_defined_at(cbase, id)) return cbase; 00485 if (cbase == rb_cObject) { 00486 VALUE tmp = RCLASS_SUPER(cbase); 00487 while (tmp) { 00488 if (rb_const_defined_at(tmp, id)) return tmp; 00489 tmp = RCLASS_SUPER(tmp); 00490 } 00491 } 00492 return 0; 00493 } 00494 00495 #ifndef USE_IC_FOR_IVAR 00496 #define USE_IC_FOR_IVAR 1 00497 #endif 00498 00499 static inline VALUE 00500 vm_getivar(VALUE obj, ID id, IC ic, rb_call_info_t *ci, int is_attr) 00501 { 00502 #if USE_IC_FOR_IVAR 00503 if (RB_TYPE_P(obj, T_OBJECT)) { 00504 VALUE val = Qundef; 00505 VALUE klass = RBASIC(obj)->klass; 00506 00507 if (LIKELY((!is_attr && (ic->ic_class == klass && ic->ic_vmstat == GET_VM_STATE_VERSION())) || 00508 (is_attr && ci->aux.index > 0))) { 00509 long index = !is_attr ? ic->ic_value.index : ci->aux.index - 1; 00510 long len = ROBJECT_NUMIV(obj); 00511 VALUE *ptr = ROBJECT_IVPTR(obj); 00512 00513 if (index < len) { 00514 val = ptr[index]; 00515 } 00516 } 00517 else { 00518 st_data_t index; 00519 long len = ROBJECT_NUMIV(obj); 00520 VALUE *ptr = ROBJECT_IVPTR(obj); 00521 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 00522 00523 if (iv_index_tbl) { 00524 if (st_lookup(iv_index_tbl, id, &index)) { 00525 if ((long)index < len) { 00526 val = ptr[index]; 00527 } 00528 if (!is_attr) { 00529 ic->ic_class = klass; 00530 ic->ic_value.index = index; 00531 ic->ic_vmstat = GET_VM_STATE_VERSION(); 00532 } 00533 else { /* call_info */ 00534 ci->aux.index = index + 1; 00535 } 00536 } 00537 } 00538 } 00539 00540 if (UNLIKELY(val == Qundef)) { 00541 if (!is_attr) rb_warning("instance variable %s not initialized", rb_id2name(id)); 00542 val = Qnil; 00543 } 00544 return val; 00545 } 00546 #endif /* USE_IC_FOR_IVAR */ 00547 if (is_attr) 00548 return rb_attr_get(obj, id); 00549 return rb_ivar_get(obj, id); 00550 } 00551 00552 static inline VALUE 00553 vm_setivar(VALUE obj, ID id, VALUE val, IC ic, rb_call_info_t *ci, int is_attr) 00554 { 00555 #if USE_IC_FOR_IVAR 00556 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) { 00557 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); 00558 } 00559 00560 rb_check_frozen(obj); 00561 00562 if (RB_TYPE_P(obj, T_OBJECT)) { 00563 VALUE klass = RBASIC(obj)->klass; 00564 st_data_t index; 00565 00566 if (LIKELY( 00567 (!is_attr && ic->ic_class == klass && ic->ic_vmstat == GET_VM_STATE_VERSION()) || 00568 (is_attr && ci->aux.index > 0))) { 00569 long index = !is_attr ? ic->ic_value.index : ci->aux.index-1; 00570 long len = ROBJECT_NUMIV(obj); 00571 VALUE *ptr = ROBJECT_IVPTR(obj); 00572 00573 if (index < len) { 00574 ptr[index] = val; 00575 return val; /* inline cache hit */ 00576 } 00577 } 00578 else { 00579 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 00580 00581 if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) { 00582 if (!is_attr) { 00583 ic->ic_class = klass; 00584 ic->ic_value.index = index; 00585 ic->ic_vmstat = GET_VM_STATE_VERSION(); 00586 } 00587 else { 00588 ci->aux.index = index + 1; 00589 } 00590 } 00591 /* fall through */ 00592 } 00593 } 00594 #endif /* USE_IC_FOR_IVAR */ 00595 return rb_ivar_set(obj, id, val); 00596 } 00597 00598 static VALUE 00599 vm_getinstancevariable(VALUE obj, ID id, IC ic) 00600 { 00601 return vm_getivar(obj, id, ic, 0, 0); 00602 } 00603 00604 static void 00605 vm_setinstancevariable(VALUE obj, ID id, VALUE val, IC ic) 00606 { 00607 vm_setivar(obj, id, val, ic, 0, 0); 00608 } 00609 00610 static VALUE 00611 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, 00612 rb_num_t throw_state, VALUE throwobj) 00613 { 00614 int state = (int)(throw_state & 0xff); 00615 int flag = (int)(throw_state & 0x8000); 00616 rb_num_t level = throw_state >> 16; 00617 00618 if (state != 0) { 00619 VALUE *pt = 0; 00620 if (flag != 0) { 00621 pt = (void *) 1; 00622 } 00623 else { 00624 if (state == TAG_BREAK) { 00625 rb_control_frame_t *cfp = GET_CFP(); 00626 VALUE *ep = GET_EP(); 00627 int is_orphan = 1; 00628 rb_iseq_t *base_iseq = GET_ISEQ(); 00629 00630 search_parent: 00631 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { 00632 if (cfp->iseq->type == ISEQ_TYPE_CLASS) { 00633 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00634 ep = cfp->ep; 00635 goto search_parent; 00636 } 00637 ep = VM_EP_PREV_EP(ep); 00638 base_iseq = base_iseq->parent_iseq; 00639 00640 while ((VALUE *) cfp < th->stack + th->stack_size) { 00641 if (cfp->ep == ep) { 00642 goto search_parent; 00643 } 00644 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00645 } 00646 rb_bug("VM (throw): can't find break base."); 00647 } 00648 00649 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 00650 /* lambda{... break ...} */ 00651 is_orphan = 0; 00652 pt = cfp->ep; 00653 state = TAG_RETURN; 00654 } 00655 else { 00656 ep = VM_EP_PREV_EP(ep); 00657 00658 while ((VALUE *)cfp < th->stack + th->stack_size) { 00659 if (cfp->ep == ep) { 00660 VALUE epc = cfp->pc - cfp->iseq->iseq_encoded; 00661 rb_iseq_t *iseq = cfp->iseq; 00662 int i; 00663 00664 for (i=0; i<iseq->catch_table_size; i++) { 00665 struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; 00666 00667 if (entry->type == CATCH_TYPE_BREAK && 00668 entry->start < epc && entry->end >= epc) { 00669 if (entry->cont == epc) { 00670 goto found; 00671 } 00672 else { 00673 break; 00674 } 00675 } 00676 } 00677 break; 00678 00679 found: 00680 pt = ep; 00681 is_orphan = 0; 00682 break; 00683 } 00684 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00685 } 00686 } 00687 00688 if (is_orphan) { 00689 rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); 00690 } 00691 } 00692 else if (state == TAG_RETRY) { 00693 rb_num_t i; 00694 pt = VM_EP_PREV_EP(GET_EP()); 00695 for (i = 0; i < level; i++) { 00696 pt = GC_GUARDED_PTR_REF((VALUE *) * pt); 00697 } 00698 } 00699 else if (state == TAG_RETURN) { 00700 rb_control_frame_t *cfp = GET_CFP(); 00701 VALUE *ep = GET_EP(); 00702 VALUE *target_lep = VM_CF_LEP(cfp); 00703 int in_class_frame = 0; 00704 00705 /* check orphan and get dfp */ 00706 while ((VALUE *) cfp < th->stack + th->stack_size) { 00707 VALUE *lep = VM_CF_LEP(cfp); 00708 00709 if (!target_lep) { 00710 target_lep = lep; 00711 } 00712 00713 if (lep == target_lep && cfp->iseq->type == ISEQ_TYPE_CLASS) { 00714 in_class_frame = 1; 00715 target_lep = 0; 00716 } 00717 00718 if (lep == target_lep) { 00719 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 00720 VALUE *tep = ep; 00721 00722 if (in_class_frame) { 00723 /* lambda {class A; ... return ...; end} */ 00724 ep = cfp->ep; 00725 goto valid_return; 00726 } 00727 00728 while (target_lep != tep) { 00729 if (cfp->ep == tep) { 00730 /* in lambda */ 00731 ep = cfp->ep; 00732 goto valid_return; 00733 } 00734 tep = VM_EP_PREV_EP(tep); 00735 } 00736 } 00737 } 00738 00739 if (cfp->ep == target_lep && cfp->iseq->type == ISEQ_TYPE_METHOD) { 00740 ep = target_lep; 00741 goto valid_return; 00742 } 00743 00744 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00745 } 00746 00747 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN); 00748 00749 valid_return: 00750 pt = ep; 00751 } 00752 else { 00753 rb_bug("isns(throw): unsupport throw type"); 00754 } 00755 } 00756 th->state = state; 00757 return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state); 00758 } 00759 else { 00760 /* continue throw */ 00761 VALUE err = throwobj; 00762 00763 if (FIXNUM_P(err)) { 00764 th->state = FIX2INT(err); 00765 } 00766 else if (SYMBOL_P(err)) { 00767 th->state = TAG_THROW; 00768 } 00769 else if (BUILTIN_TYPE(err) == T_NODE) { 00770 th->state = GET_THROWOBJ_STATE(err); 00771 } 00772 else { 00773 th->state = TAG_RAISE; 00774 /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/ 00775 } 00776 return err; 00777 } 00778 } 00779 00780 static inline void 00781 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag) 00782 { 00783 int is_splat = flag & 0x01; 00784 rb_num_t space_size = num + is_splat; 00785 VALUE *base = cfp->sp, *ptr; 00786 rb_num_t len; 00787 00788 if (!RB_TYPE_P(ary, T_ARRAY)) { 00789 ary = rb_ary_to_ary(ary); 00790 } 00791 00792 cfp->sp += space_size; 00793 00794 ptr = RARRAY_PTR(ary); 00795 len = (rb_num_t)RARRAY_LEN(ary); 00796 00797 if (flag & 0x02) { 00798 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */ 00799 rb_num_t i = 0, j; 00800 00801 if (len < num) { 00802 for (i=0; i<num-len; i++) { 00803 *base++ = Qnil; 00804 } 00805 } 00806 for (j=0; i<num; i++, j++) { 00807 VALUE v = ptr[len - j - 1]; 00808 *base++ = v; 00809 } 00810 if (is_splat) { 00811 *base = rb_ary_new4(len - j, ptr); 00812 } 00813 } 00814 else { 00815 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */ 00816 rb_num_t i; 00817 VALUE *bptr = &base[space_size - 1]; 00818 00819 for (i=0; i<num; i++) { 00820 if (len <= i) { 00821 for (; i<num; i++) { 00822 *bptr-- = Qnil; 00823 } 00824 break; 00825 } 00826 *bptr-- = ptr[i]; 00827 } 00828 if (is_splat) { 00829 if (num > len) { 00830 *bptr = rb_ary_new(); 00831 } 00832 else { 00833 *bptr = rb_ary_new4(len - num, ptr + num); 00834 } 00835 } 00836 } 00837 RB_GC_GUARD(ary); 00838 } 00839 00840 static VALUE vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci); 00841 00842 static void 00843 vm_search_method(rb_call_info_t *ci, VALUE recv) 00844 { 00845 VALUE klass = CLASS_OF(recv); 00846 00847 #if OPT_INLINE_METHOD_CACHE 00848 if (LIKELY(GET_VM_STATE_VERSION() == ci->vmstat && klass == ci->klass)) { 00849 /* cache hit! */ 00850 } 00851 else { 00852 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); 00853 ci->klass = klass; 00854 ci->vmstat = GET_VM_STATE_VERSION(); 00855 ci->call = vm_call_general; 00856 } 00857 #else 00858 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); 00859 ci->call = vm_call_general; 00860 ci->klass = klass; 00861 #endif 00862 } 00863 00864 static inline int 00865 check_cfunc(const rb_method_entry_t *me, VALUE (*func)()) 00866 { 00867 if (me && me->def->type == VM_METHOD_TYPE_CFUNC && 00868 me->def->body.cfunc.func == func) { 00869 return 1; 00870 } 00871 else { 00872 return 0; 00873 } 00874 } 00875 00876 static 00877 #ifndef NO_BIG_INLINE 00878 inline 00879 #endif 00880 VALUE 00881 opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci) 00882 { 00883 if (FIXNUM_2_P(recv, obj) && 00884 BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) { 00885 return (recv == obj) ? Qtrue : Qfalse; 00886 } 00887 else if (FLONUM_2_P(recv, obj) && 00888 BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) { 00889 return (recv == obj) ? Qtrue : Qfalse; 00890 } 00891 else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { 00892 if (HEAP_CLASS_OF(recv) == rb_cFloat && 00893 HEAP_CLASS_OF(obj) == rb_cFloat && 00894 BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) { 00895 double a = RFLOAT_VALUE(recv); 00896 double b = RFLOAT_VALUE(obj); 00897 00898 if (isnan(a) || isnan(b)) { 00899 return Qfalse; 00900 } 00901 return (a == b) ? Qtrue : Qfalse; 00902 } 00903 else if (HEAP_CLASS_OF(recv) == rb_cString && 00904 HEAP_CLASS_OF(obj) == rb_cString && 00905 BASIC_OP_UNREDEFINED_P(BOP_EQ, STRING_REDEFINED_OP_FLAG)) { 00906 return rb_str_equal(recv, obj); 00907 } 00908 } 00909 00910 { 00911 vm_search_method(ci, recv); 00912 00913 if (check_cfunc(ci->me, rb_obj_equal)) { 00914 return recv == obj ? Qtrue : Qfalse; 00915 } 00916 } 00917 00918 return Qundef; 00919 } 00920 00921 static VALUE 00922 check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) 00923 { 00924 switch (type) { 00925 case VM_CHECKMATCH_TYPE_WHEN: 00926 return pattern; 00927 case VM_CHECKMATCH_TYPE_CASE: 00928 return rb_funcall2(pattern, idEqq, 1, &target); 00929 case VM_CHECKMATCH_TYPE_RESCUE: { 00930 if (!rb_obj_is_kind_of(pattern, rb_cModule)) { 00931 rb_raise(rb_eTypeError, "class or module required for rescue clause"); 00932 } 00933 return RTEST(rb_funcall2(pattern, idEqq, 1, &target)); 00934 } 00935 default: 00936 rb_bug("check_match: unreachable"); 00937 } 00938 } 00939 00940 00941 #if defined(_MSC_VER) && _MSC_VER < 1300 00942 #define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse; 00943 #else 00944 #define CHECK_CMP_NAN(a, b) /* do nothing */ 00945 #endif 00946 00947 static inline VALUE 00948 double_cmp_lt(double a, double b) 00949 { 00950 CHECK_CMP_NAN(a, b); 00951 return a < b ? Qtrue : Qfalse; 00952 } 00953 00954 static inline VALUE 00955 double_cmp_le(double a, double b) 00956 { 00957 CHECK_CMP_NAN(a, b); 00958 return a <= b ? Qtrue : Qfalse; 00959 } 00960 00961 static inline VALUE 00962 double_cmp_gt(double a, double b) 00963 { 00964 CHECK_CMP_NAN(a, b); 00965 return a > b ? Qtrue : Qfalse; 00966 } 00967 00968 static inline VALUE 00969 double_cmp_ge(double a, double b) 00970 { 00971 CHECK_CMP_NAN(a, b); 00972 return a >= b ? Qtrue : Qfalse; 00973 } 00974 00975 static VALUE * 00976 vm_base_ptr(rb_control_frame_t *cfp) 00977 { 00978 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00979 VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1; 00980 00981 if (cfp->iseq->type == ISEQ_TYPE_METHOD) { 00982 /* adjust `self' */ 00983 bp += 1; 00984 } 00985 00986 #if VM_DEBUG_BP_CHECK 00987 if (bp != cfp->bp_check) { 00988 fprintf(stderr, "bp_check: %ld, bp: %ld\n", 00989 (long)(cfp->bp_check - GET_THREAD()->stack), 00990 (long)(bp - GET_THREAD()->stack)); 00991 rb_bug("vm_base_ptr: unreachable"); 00992 } 00993 #endif 00994 00995 return bp; 00996 } 00997 00998 /* method call processes with call_info */ 00999 01000 static void 01001 vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01002 { 01003 #define SAVE_RESTORE_CI(expr, ci) do { \ 01004 int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \ 01005 expr; \ 01006 (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \ 01007 } while (0) 01008 01009 if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) { 01010 rb_proc_t *po; 01011 VALUE proc; 01012 01013 proc = *(--cfp->sp); 01014 01015 if (proc != Qnil) { 01016 if (!rb_obj_is_proc(proc)) { 01017 VALUE b; 01018 01019 SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci); 01020 01021 if (NIL_P(b) || !rb_obj_is_proc(b)) { 01022 rb_raise(rb_eTypeError, 01023 "wrong argument type %s (expected Proc)", 01024 rb_obj_classname(proc)); 01025 } 01026 proc = b; 01027 } 01028 GetProcPtr(proc, po); 01029 ci->blockptr = &po->block; 01030 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; 01031 } 01032 } 01033 else if (ci->blockiseq != 0) { /* likely */ 01034 ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); 01035 ci->blockptr->iseq = ci->blockiseq; 01036 ci->blockptr->proc = 0; 01037 } 01038 01039 /* expand top of stack? */ 01040 01041 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) { 01042 VALUE ary = *(cfp->sp - 1); 01043 VALUE *ptr; 01044 int i; 01045 VALUE tmp; 01046 01047 SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci); 01048 01049 if (NIL_P(tmp)) { 01050 /* do nothing */ 01051 } 01052 else { 01053 long len = RARRAY_LEN(tmp); 01054 ptr = RARRAY_PTR(tmp); 01055 cfp->sp -= 1; 01056 01057 CHECK_VM_STACK_OVERFLOW(cfp, len); 01058 01059 for (i = 0; i < len; i++) { 01060 *cfp->sp++ = ptr[i]; 01061 } 01062 ci->argc += i-1; 01063 } 01064 } 01065 } 01066 01067 static int 01068 separate_symbol(st_data_t key, st_data_t value, st_data_t arg) 01069 { 01070 VALUE *kwdhash = (VALUE *)arg; 01071 01072 if (!SYMBOL_P(key)) kwdhash++; 01073 if (!*kwdhash) *kwdhash = rb_hash_new(); 01074 rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value); 01075 return ST_CONTINUE; 01076 } 01077 01078 static VALUE 01079 extract_keywords(VALUE *orighash) 01080 { 01081 VALUE parthash[2] = {0, 0}; 01082 VALUE hash = *orighash; 01083 01084 if (RHASH_EMPTY_P(hash)) { 01085 *orighash = 0; 01086 return hash; 01087 } 01088 st_foreach(RHASH_TBL(hash), separate_symbol, (st_data_t)&parthash); 01089 *orighash = parthash[1]; 01090 return parthash[0]; 01091 } 01092 01093 static inline int 01094 vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd) 01095 { 01096 VALUE keyword_hash, orig_hash; 01097 int i, j; 01098 01099 if (argc > m && 01100 !NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) && 01101 (keyword_hash = extract_keywords(&orig_hash)) != 0) { 01102 if (!orig_hash) { 01103 argc--; 01104 } 01105 else { 01106 orig_argv[argc-1] = orig_hash; 01107 } 01108 if (iseq->arg_keyword_check) { 01109 for (i = j = 0; i < iseq->arg_keywords; i++) { 01110 if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++; 01111 } 01112 if (RHASH_TBL(keyword_hash)->num_entries > (unsigned int) j) { 01113 unknown_keyword_error(iseq, keyword_hash); 01114 } 01115 } 01116 } 01117 else { 01118 keyword_hash = rb_hash_new(); 01119 } 01120 01121 *kwd = keyword_hash; 01122 01123 return argc; 01124 } 01125 01126 static inline int 01127 vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *orig_argv) 01128 { 01129 const int m = iseq->argc; 01130 const int opts = iseq->arg_opts - (iseq->arg_opts > 0); 01131 const int min = m + iseq->arg_post_len; 01132 const int max = (iseq->arg_rest == -1) ? m + opts + iseq->arg_post_len : UNLIMITED_ARGUMENTS; 01133 const int orig_argc = ci->argc; 01134 int argc = orig_argc; 01135 VALUE *argv = orig_argv; 01136 VALUE keyword_hash = Qnil; 01137 rb_num_t opt_pc = 0; 01138 01139 th->mark_stack_len = argc + iseq->arg_size; 01140 01141 /* keyword argument */ 01142 if (iseq->arg_keyword != -1) { 01143 argc = vm_callee_setup_keyword_arg(iseq, argc, m, orig_argv, &keyword_hash); 01144 } 01145 01146 /* mandatory */ 01147 if ((argc < min) || (argc > max && max != UNLIMITED_ARGUMENTS)) { 01148 argument_error(iseq, argc, min, max); 01149 } 01150 01151 argv += m; 01152 argc -= m; 01153 01154 /* post arguments */ 01155 if (iseq->arg_post_len) { 01156 if (!(orig_argc < iseq->arg_post_start)) { 01157 VALUE *new_argv = ALLOCA_N(VALUE, argc); 01158 MEMCPY(new_argv, argv, VALUE, argc); 01159 argv = new_argv; 01160 } 01161 01162 MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len], 01163 VALUE, iseq->arg_post_len); 01164 } 01165 01166 /* opt arguments */ 01167 if (iseq->arg_opts) { 01168 if (argc > opts) { 01169 argc -= opts; 01170 argv += opts; 01171 opt_pc = iseq->arg_opt_table[opts]; /* no opt */ 01172 } 01173 else { 01174 int i; 01175 for (i = argc; i<opts; i++) { 01176 orig_argv[i + m] = Qnil; 01177 } 01178 opt_pc = iseq->arg_opt_table[argc]; 01179 argc = 0; 01180 } 01181 } 01182 01183 /* rest arguments */ 01184 if (iseq->arg_rest != -1) { 01185 orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv); 01186 argc = 0; 01187 } 01188 01189 /* keyword argument */ 01190 if (iseq->arg_keyword != -1) { 01191 orig_argv[iseq->arg_keyword] = keyword_hash; 01192 } 01193 01194 /* block arguments */ 01195 if (iseq->arg_block != -1) { 01196 VALUE blockval = Qnil; 01197 const rb_block_t *blockptr = ci->blockptr; 01198 01199 if (blockptr) { 01200 /* make Proc object */ 01201 if (blockptr->proc == 0) { 01202 rb_proc_t *proc; 01203 blockval = rb_vm_make_proc(th, blockptr, rb_cProc); 01204 GetProcPtr(blockval, proc); 01205 ci->blockptr = &proc->block; 01206 } 01207 else { 01208 blockval = blockptr->proc; 01209 } 01210 } 01211 01212 orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ 01213 } 01214 01215 th->mark_stack_len = 0; 01216 return (int)opt_pc; 01217 } 01218 01219 static VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01220 static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01221 static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01222 01223 #define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \ 01224 if (LIKELY((iseq)->arg_simple & 0x01)) { \ 01225 /* simple check */ \ 01226 if ((ci)->argc != (iseq)->argc) { \ 01227 argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \ 01228 } \ 01229 (ci)->aux.opt_pc = 0; \ 01230 CI_SET_FASTPATH((ci), UNLIKELY((ci)->flag & VM_CALL_TAILCALL) ? vm_call_iseq_setup_tailcall : vm_call_iseq_setup_normal, !(is_lambda) && !((ci)->me->flag & NOEX_PROTECTED)); \ 01231 } \ 01232 else { \ 01233 (ci)->aux.opt_pc = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \ 01234 } 01235 01236 static VALUE 01237 vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01238 { 01239 VM_CALLEE_SETUP_ARG(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0); 01240 return vm_call_iseq_setup_2(th, cfp, ci); 01241 } 01242 01243 static VALUE 01244 vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01245 { 01246 if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) { 01247 return vm_call_iseq_setup_normal(th, cfp, ci); 01248 } 01249 else { 01250 return vm_call_iseq_setup_tailcall(th, cfp, ci); 01251 } 01252 } 01253 01254 static inline VALUE 01255 vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01256 { 01257 int i; 01258 VALUE *argv = cfp->sp - ci->argc; 01259 rb_iseq_t *iseq = ci->me->def->body.iseq; 01260 VALUE *sp = argv + iseq->arg_size; 01261 01262 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); 01263 01264 /* clear local variables */ 01265 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 01266 *sp++ = Qnil; 01267 } 01268 01269 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, 01270 VM_ENVVAL_BLOCK_PTR(ci->blockptr), 01271 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); 01272 01273 cfp->sp = argv - 1 /* recv */; 01274 return Qundef; 01275 } 01276 01277 static inline VALUE 01278 vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01279 { 01280 int i; 01281 VALUE *argv = cfp->sp - ci->argc; 01282 rb_iseq_t *iseq = ci->me->def->body.iseq; 01283 VALUE *src_argv = argv; 01284 VALUE *sp_orig, *sp; 01285 VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0; 01286 01287 cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */ 01288 01289 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); 01290 RUBY_VM_CHECK_INTS(th); 01291 01292 sp_orig = sp = cfp->sp; 01293 01294 /* push self */ 01295 sp[0] = ci->recv; 01296 sp++; 01297 01298 /* copy arguments */ 01299 for (i=0; i < iseq->arg_size; i++) { 01300 *sp++ = src_argv[i]; 01301 } 01302 01303 /* clear local variables */ 01304 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 01305 *sp++ = Qnil; 01306 } 01307 01308 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, 01309 ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), 01310 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); 01311 01312 cfp->sp = sp_orig; 01313 return Qundef; 01314 } 01315 01316 static VALUE 01317 call_cfunc_m2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01318 { 01319 return (*func)(recv, rb_ary_new4(argc, argv)); 01320 } 01321 01322 static VALUE 01323 call_cfunc_m1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01324 { 01325 return (*func)(argc, argv, recv); 01326 } 01327 01328 static VALUE 01329 call_cfunc_0(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01330 { 01331 return (*func)(recv); 01332 } 01333 01334 static VALUE 01335 call_cfunc_1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01336 { 01337 return (*func)(recv, argv[0]); 01338 } 01339 01340 static VALUE 01341 call_cfunc_2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01342 { 01343 return (*func)(recv, argv[0], argv[1]); 01344 } 01345 01346 static VALUE 01347 call_cfunc_3(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01348 { 01349 return (*func)(recv, argv[0], argv[1], argv[2]); 01350 } 01351 01352 static VALUE 01353 call_cfunc_4(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01354 { 01355 return (*func)(recv, argv[0], argv[1], argv[2], argv[3]); 01356 } 01357 01358 static VALUE 01359 call_cfunc_5(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01360 { 01361 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]); 01362 } 01363 01364 static VALUE 01365 call_cfunc_6(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01366 { 01367 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); 01368 } 01369 01370 static VALUE 01371 call_cfunc_7(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01372 { 01373 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); 01374 } 01375 01376 static VALUE 01377 call_cfunc_8(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01378 { 01379 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); 01380 } 01381 01382 static VALUE 01383 call_cfunc_9(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01384 { 01385 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); 01386 } 01387 01388 static VALUE 01389 call_cfunc_10(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01390 { 01391 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]); 01392 } 01393 01394 static VALUE 01395 call_cfunc_11(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01396 { 01397 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); 01398 } 01399 01400 static VALUE 01401 call_cfunc_12(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01402 { 01403 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]); 01404 } 01405 01406 static VALUE 01407 call_cfunc_13(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01408 { 01409 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]); 01410 } 01411 01412 static VALUE 01413 call_cfunc_14(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01414 { 01415 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]); 01416 } 01417 01418 static VALUE 01419 call_cfunc_15(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01420 { 01421 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]); 01422 } 01423 01424 #ifndef VM_PROFILE 01425 #define VM_PROFILE 0 01426 #endif 01427 01428 #if VM_PROFILE 01429 static int vm_profile_counter[4]; 01430 #define VM_PROFILE_UP(x) (vm_profile_counter[x]++) 01431 #define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result) 01432 static void vm_profile_show_result(void) 01433 { 01434 fprintf(stderr, "VM Profile results: \n"); 01435 fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]); 01436 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]); 01437 fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]); 01438 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]); 01439 } 01440 #else 01441 #define VM_PROFILE_UP(x) 01442 #define VM_PROFILE_ATEXIT() 01443 #endif 01444 01445 static VALUE 01446 vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01447 { 01448 VALUE val; 01449 const rb_method_entry_t *me = ci->me; 01450 const rb_method_cfunc_t *cfunc = &me->def->body.cfunc; 01451 int len = cfunc->argc; 01452 01453 /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */ 01454 VALUE recv = ci->recv; 01455 VALUE defined_class = ci->defined_class; 01456 rb_block_t *blockptr = ci->blockptr; 01457 int argc = ci->argc; 01458 01459 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); 01460 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef); 01461 01462 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, 01463 VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me); 01464 01465 if (len >= 0) rb_check_arity(argc, len, len); 01466 01467 reg_cfp->sp -= argc + 1; 01468 VM_PROFILE_UP(0); 01469 val = (*cfunc->invoker)(cfunc->func, recv, argc, reg_cfp->sp + 1); 01470 01471 if (reg_cfp != th->cfp + 1) { 01472 rb_bug("vm_call_cfunc - cfp consistency error"); 01473 } 01474 01475 vm_pop_frame(th); 01476 01477 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); 01478 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); 01479 01480 return val; 01481 } 01482 01483 #if OPT_CALL_CFUNC_WITHOUT_FRAME 01484 static VALUE 01485 vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01486 { 01487 VALUE val; 01488 int argc = ci->argc; 01489 VALUE *argv = STACK_ADDR_FROM_TOP(argc); 01490 const rb_method_cfunc_t *cfunc = &ci->me->def->body.cfunc; 01491 01492 th->passed_ci = ci; 01493 reg_cfp->sp -= argc + 1; 01494 ci->aux.inc_sp = argc + 1; 01495 VM_PROFILE_UP(0); 01496 val = (*cfunc->invoker)(cfunc->func, ci, argv); 01497 01498 /* check */ 01499 if (reg_cfp == th->cfp) { /* no frame push */ 01500 if (UNLIKELY(th->passed_ci != ci)) { 01501 rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci); 01502 } 01503 th->passed_ci = 0; 01504 } 01505 else { 01506 if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) { 01507 rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1); 01508 } 01509 vm_pop_frame(th); 01510 VM_PROFILE_UP(1); 01511 } 01512 01513 return val; 01514 } 01515 01516 static VALUE 01517 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01518 { 01519 VALUE val; 01520 const rb_method_entry_t *me = ci->me; 01521 int len = me->def->body.cfunc.argc; 01522 VALUE recv = ci->recv; 01523 01524 if (len >= 0) rb_check_arity(ci->argc, len, len); 01525 01526 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); 01527 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil); 01528 01529 if (!(ci->me->flag & NOEX_PROTECTED) && 01530 !(ci->flag & VM_CALL_ARGS_SPLAT)) { 01531 CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1); 01532 } 01533 val = vm_call_cfunc_latter(th, reg_cfp, ci); 01534 01535 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); 01536 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); 01537 01538 return val; 01539 } 01540 01541 void 01542 vm_call_cfunc_push_frame(rb_thread_t *th) 01543 { 01544 rb_call_info_t *ci = th->passed_ci; 01545 const rb_method_entry_t *me = ci->me; 01546 th->passed_ci = 0; 01547 01548 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, 01549 VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me); 01550 01551 if (ci->call != vm_call_general) { 01552 ci->call = vm_call_cfunc_with_frame; 01553 } 01554 } 01555 #else /* OPT_CALL_CFUNC_WITHOUT_FRAME */ 01556 static VALUE 01557 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01558 { 01559 return vm_call_cfunc_with_frame(th, reg_cfp, ci); 01560 } 01561 #endif 01562 01563 static VALUE 01564 vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01565 { 01566 VALUE val = vm_getivar(ci->recv, ci->me->def->body.attr.id, 0, ci, 1); 01567 cfp->sp -= 1; 01568 return val; 01569 } 01570 01571 static VALUE 01572 vm_call_attrset(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01573 { 01574 VALUE val = vm_setivar(ci->recv, ci->me->def->body.attr.id, *(cfp->sp - 1), 0, ci, 1); 01575 cfp->sp -= 2; 01576 return val; 01577 } 01578 01579 static inline VALUE 01580 vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv) 01581 { 01582 rb_proc_t *proc; 01583 VALUE val; 01584 01585 RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id); 01586 EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil); 01587 01588 /* control block frame */ 01589 th->passed_me = ci->me; 01590 GetProcPtr(ci->me->def->body.proc, proc); 01591 val = vm_invoke_proc(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr); 01592 01593 EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, ci->recv, ci->me->called_id, ci->me->klass, val); 01594 RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->me->klass, ci->me->called_id); 01595 01596 return val; 01597 } 01598 01599 static VALUE 01600 vm_call_bmethod(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01601 { 01602 VALUE *argv = ALLOCA_N(VALUE, ci->argc); 01603 MEMCPY(argv, cfp->sp - ci->argc, VALUE, ci->argc); 01604 cfp->sp += - ci->argc - 1; 01605 01606 return vm_call_bmethod_body(th, ci, argv); 01607 } 01608 01609 static 01610 #ifdef _MSC_VER 01611 __forceinline 01612 #else 01613 inline 01614 #endif 01615 VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01616 01617 static VALUE 01618 vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01619 { 01620 int i = ci->argc - 1; 01621 VALUE sym; 01622 rb_call_info_t ci_entry; 01623 01624 if (ci->argc == 0) { 01625 rb_raise(rb_eArgError, "no method name given"); 01626 } 01627 01628 ci_entry = *ci; /* copy ci entry */ 01629 ci = &ci_entry; 01630 01631 sym = TOPN(i); 01632 01633 if (SYMBOL_P(sym)) { 01634 ci->mid = SYM2ID(sym); 01635 } 01636 else if (!(ci->mid = rb_check_id(&sym))) { 01637 if (rb_method_basic_definition_p(CLASS_OF(ci->recv), idMethodMissing)) { 01638 VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i)); 01639 rb_exc_raise(exc); 01640 } 01641 ci->mid = rb_to_id(sym); 01642 } 01643 01644 /* shift arguments */ 01645 if (i > 0) { 01646 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); 01647 } 01648 ci->me = 01649 rb_method_entry_without_refinements(CLASS_OF(ci->recv), 01650 ci->mid, &ci->defined_class); 01651 ci->argc -= 1; 01652 DEC_SP(1); 01653 01654 ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; 01655 01656 return vm_call_method(th, reg_cfp, ci); 01657 } 01658 01659 static VALUE 01660 vm_call_opt_call(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01661 { 01662 rb_proc_t *proc; 01663 int argc = ci->argc; 01664 VALUE *argv = ALLOCA_N(VALUE, argc); 01665 GetProcPtr(ci->recv, proc); 01666 MEMCPY(argv, cfp->sp - argc, VALUE, argc); 01667 cfp->sp -= argc + 1; 01668 01669 return rb_vm_invoke_proc(th, proc, argc, argv, ci->blockptr); 01670 } 01671 01672 static VALUE 01673 vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01674 { 01675 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc); 01676 rb_call_info_t ci_entry; 01677 01678 ci_entry.flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; 01679 ci_entry.argc = ci->argc+1; 01680 ci_entry.mid = idMethodMissing; 01681 ci_entry.blockptr = ci->blockptr; 01682 ci_entry.recv = ci->recv; 01683 ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class); 01684 01685 /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */ 01686 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1); 01687 if (ci->argc > 0) { 01688 MEMMOVE(argv+1, argv, VALUE, ci->argc); 01689 } 01690 argv[0] = ID2SYM(ci->mid); 01691 INC_SP(1); 01692 01693 th->method_missing_reason = ci->aux.missing_reason; 01694 return vm_call_method(th, reg_cfp, &ci_entry); 01695 } 01696 01697 static inline VALUE 01698 find_refinement(VALUE refinements, VALUE klass) 01699 { 01700 if (NIL_P(refinements)) { 01701 return Qnil; 01702 } 01703 return rb_hash_lookup(refinements, klass); 01704 } 01705 01706 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2); 01707 static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci); 01708 01709 static rb_control_frame_t * 01710 current_method_entry(rb_thread_t *th, rb_control_frame_t *cfp) 01711 { 01712 rb_control_frame_t *top_cfp = cfp; 01713 01714 if (cfp->iseq && cfp->iseq->type == ISEQ_TYPE_BLOCK) { 01715 rb_iseq_t *local_iseq = cfp->iseq->local_iseq; 01716 do { 01717 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01718 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 01719 /* TODO: orphan block */ 01720 return top_cfp; 01721 } 01722 } while (cfp->iseq != local_iseq); 01723 } 01724 return cfp; 01725 } 01726 01727 static 01728 #ifdef _MSC_VER 01729 __forceinline 01730 #else 01731 inline 01732 #endif 01733 VALUE 01734 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01735 { 01736 int enable_fastpath = 1; 01737 rb_call_info_t ci_temp; 01738 01739 start_method_dispatch: 01740 if (ci->me != 0) { 01741 if ((ci->me->flag == 0)) { 01742 normal_method_dispatch: 01743 switch (ci->me->def->type) { 01744 case VM_METHOD_TYPE_ISEQ:{ 01745 CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath); 01746 return vm_call_iseq_setup(th, cfp, ci); 01747 } 01748 case VM_METHOD_TYPE_NOTIMPLEMENTED: 01749 case VM_METHOD_TYPE_CFUNC: 01750 CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath); 01751 return vm_call_cfunc(th, cfp, ci); 01752 case VM_METHOD_TYPE_ATTRSET:{ 01753 rb_check_arity(ci->argc, 1, 1); 01754 ci->aux.index = 0; 01755 CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); 01756 return vm_call_attrset(th, cfp, ci); 01757 } 01758 case VM_METHOD_TYPE_IVAR:{ 01759 rb_check_arity(ci->argc, 0, 0); 01760 ci->aux.index = 0; 01761 CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); 01762 return vm_call_ivar(th, cfp, ci); 01763 } 01764 case VM_METHOD_TYPE_MISSING:{ 01765 ci->aux.missing_reason = 0; 01766 CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath); 01767 return vm_call_method_missing(th, cfp, ci); 01768 } 01769 case VM_METHOD_TYPE_BMETHOD:{ 01770 CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath); 01771 return vm_call_bmethod(th, cfp, ci); 01772 } 01773 case VM_METHOD_TYPE_ZSUPER:{ 01774 VALUE klass; 01775 01776 zsuper_method_dispatch: 01777 klass = RCLASS_SUPER(ci->me->klass); 01778 ci_temp = *ci; 01779 ci = &ci_temp; 01780 01781 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); 01782 01783 if (ci->me != 0) { 01784 goto normal_method_dispatch; 01785 } 01786 else { 01787 goto start_method_dispatch; 01788 } 01789 } 01790 case VM_METHOD_TYPE_OPTIMIZED:{ 01791 switch (ci->me->def->body.optimize_type) { 01792 case OPTIMIZED_METHOD_TYPE_SEND: 01793 CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath); 01794 return vm_call_opt_send(th, cfp, ci); 01795 case OPTIMIZED_METHOD_TYPE_CALL: 01796 CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath); 01797 return vm_call_opt_call(th, cfp, ci); 01798 default: 01799 rb_bug("vm_call_method: unsupported optimized method type (%d)", 01800 ci->me->def->body.optimize_type); 01801 } 01802 break; 01803 } 01804 case VM_METHOD_TYPE_UNDEF: 01805 break; 01806 case VM_METHOD_TYPE_REFINED:{ 01807 NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep); 01808 VALUE refinements = cref ? cref->nd_refinements : Qnil; 01809 VALUE refinement, defined_class; 01810 rb_method_entry_t *me; 01811 01812 refinement = find_refinement(refinements, 01813 ci->defined_class); 01814 if (NIL_P(refinement)) { 01815 goto no_refinement_dispatch; 01816 } 01817 me = rb_method_entry(refinement, ci->mid, &defined_class); 01818 if (me) { 01819 if (ci->call == vm_call_super_method) { 01820 rb_control_frame_t *top_cfp = current_method_entry(th, cfp); 01821 if (top_cfp->me && 01822 rb_method_definition_eq(me->def, top_cfp->me->def)) { 01823 goto no_refinement_dispatch; 01824 } 01825 } 01826 ci->me = me; 01827 ci->defined_class = defined_class; 01828 if (me->def->type != VM_METHOD_TYPE_REFINED) { 01829 goto normal_method_dispatch; 01830 } 01831 } 01832 01833 no_refinement_dispatch: 01834 if (ci->me->def->body.orig_me) { 01835 ci->me = ci->me->def->body.orig_me; 01836 goto normal_method_dispatch; 01837 } 01838 else { 01839 goto zsuper_method_dispatch; 01840 } 01841 } 01842 } 01843 rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type); 01844 } 01845 else { 01846 int noex_safe; 01847 if (!(ci->flag & VM_CALL_FCALL) && (ci->me->flag & NOEX_MASK) & NOEX_PRIVATE) { 01848 int stat = NOEX_PRIVATE; 01849 01850 if (ci->flag & VM_CALL_VCALL) { 01851 stat |= NOEX_VCALL; 01852 } 01853 ci->aux.missing_reason = stat; 01854 CI_SET_FASTPATH(ci, vm_call_method_missing, 1); 01855 return vm_call_method_missing(th, cfp, ci); 01856 } 01857 else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) { 01858 enable_fastpath = 0; 01859 if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) { 01860 ci->aux.missing_reason = NOEX_PROTECTED; 01861 return vm_call_method_missing(th, cfp, ci); 01862 } 01863 else { 01864 goto normal_method_dispatch; 01865 } 01866 } 01867 else if ((noex_safe = NOEX_SAFE(ci->me->flag)) > th->safe_level && (noex_safe > 2)) { 01868 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(ci->mid)); 01869 } 01870 else { 01871 goto normal_method_dispatch; 01872 } 01873 } 01874 } 01875 else { 01876 /* method missing */ 01877 int stat = 0; 01878 if (ci->flag & VM_CALL_VCALL) { 01879 stat |= NOEX_VCALL; 01880 } 01881 if (ci->flag & VM_CALL_SUPER) { 01882 stat |= NOEX_SUPER; 01883 } 01884 if (ci->mid == idMethodMissing) { 01885 rb_control_frame_t *reg_cfp = cfp; 01886 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc); 01887 rb_raise_method_missing(th, ci->argc, argv, ci->recv, stat); 01888 } 01889 else { 01890 ci->aux.missing_reason = stat; 01891 CI_SET_FASTPATH(ci, vm_call_method_missing, 1); 01892 return vm_call_method_missing(th, cfp, ci); 01893 } 01894 } 01895 01896 rb_bug("vm_call_method: unreachable"); 01897 } 01898 01899 static VALUE 01900 vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01901 { 01902 return vm_call_method(th, reg_cfp, ci); 01903 } 01904 01905 static VALUE 01906 vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01907 { 01908 return vm_call_method(th, reg_cfp, ci); 01909 } 01910 01911 /* super */ 01912 01913 static inline VALUE 01914 vm_search_normal_superclass(VALUE klass) 01915 { 01916 if (BUILTIN_TYPE(klass) == T_ICLASS && 01917 FL_TEST(RBASIC(klass)->klass, RMODULE_IS_REFINEMENT)) { 01918 klass = RBASIC(klass)->klass; 01919 } 01920 klass = RCLASS_ORIGIN(klass); 01921 return RCLASS_SUPER(klass); 01922 } 01923 01924 static void 01925 vm_super_outside(void) 01926 { 01927 rb_raise(rb_eNoMethodError, "super called outside of method"); 01928 } 01929 01930 static int 01931 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci) 01932 { 01933 while (iseq && !iseq->klass) { 01934 iseq = iseq->parent_iseq; 01935 } 01936 01937 if (iseq == 0) { 01938 return -1; 01939 } 01940 01941 ci->mid = iseq->defined_method_id; 01942 01943 if (iseq != iseq->local_iseq) { 01944 /* defined by Module#define_method() */ 01945 rb_control_frame_t *lcfp = GET_CFP(); 01946 01947 if (!sigval) { 01948 /* zsuper */ 01949 return -2; 01950 } 01951 01952 while (lcfp->iseq != iseq) { 01953 rb_thread_t *th = GET_THREAD(); 01954 VALUE *tep = VM_EP_PREV_EP(lcfp->ep); 01955 while (1) { 01956 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); 01957 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) { 01958 return -1; 01959 } 01960 if (lcfp->ep == tep) { 01961 break; 01962 } 01963 } 01964 } 01965 01966 /* temporary measure for [Bug #2420] [Bug #3136] */ 01967 if (!lcfp->me) { 01968 return -1; 01969 } 01970 01971 ci->mid = lcfp->me->def->original_id; 01972 ci->klass = vm_search_normal_superclass(lcfp->klass); 01973 } 01974 else { 01975 ci->klass = vm_search_normal_superclass(reg_cfp->klass); 01976 } 01977 01978 return 0; 01979 } 01980 01981 static void 01982 vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01983 { 01984 VALUE current_defined_class; 01985 rb_iseq_t *iseq = GET_ISEQ(); 01986 VALUE sigval = TOPN(ci->orig_argc); 01987 01988 current_defined_class = GET_CFP()->klass; 01989 if (NIL_P(current_defined_class)) { 01990 vm_super_outside(); 01991 } 01992 01993 if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) { 01994 current_defined_class = RCLASS_REFINED_CLASS(current_defined_class); 01995 } 01996 01997 if (!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) && 01998 !rb_obj_is_kind_of(ci->recv, current_defined_class)) { 01999 VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ? 02000 RBASIC(current_defined_class)->klass : current_defined_class; 02001 02002 rb_raise(rb_eTypeError, 02003 "self has wrong type to call super in this context: " 02004 "%s (expected %s)", 02005 rb_obj_classname(ci->recv), rb_class2name(m)); 02006 } 02007 02008 switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) { 02009 case -1: 02010 vm_super_outside(); 02011 case -2: 02012 rb_raise(rb_eRuntimeError, 02013 "implicit argument passing of super from method defined" 02014 " by define_method() is not supported." 02015 " Specify all arguments explicitly."); 02016 } 02017 02018 /* TODO: use inline cache */ 02019 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); 02020 ci->call = vm_call_super_method; 02021 02022 while (iseq && !iseq->klass) { 02023 iseq = iseq->parent_iseq; 02024 } 02025 02026 if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) { 02027 ci->klass = RCLASS_SUPER(ci->defined_class); 02028 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); 02029 } 02030 } 02031 02032 /* yield */ 02033 02034 static inline int 02035 block_proc_is_lambda(const VALUE procval) 02036 { 02037 rb_proc_t *proc; 02038 02039 if (procval) { 02040 GetProcPtr(procval, proc); 02041 return proc->is_lambda; 02042 } 02043 else { 02044 return 0; 02045 } 02046 } 02047 02048 static inline VALUE 02049 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, 02050 VALUE self, int argc, const VALUE *argv, 02051 const rb_block_t *blockargptr) 02052 { 02053 NODE *ifunc = (NODE *) block->iseq; 02054 VALUE val, arg, blockarg; 02055 int lambda = block_proc_is_lambda(block->proc); 02056 02057 if (lambda) { 02058 arg = rb_ary_new4(argc, argv); 02059 } 02060 else if (argc == 0) { 02061 arg = Qnil; 02062 } 02063 else { 02064 arg = argv[0]; 02065 } 02066 02067 if (blockargptr) { 02068 if (blockargptr->proc) { 02069 blockarg = blockargptr->proc; 02070 } 02071 else { 02072 blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); 02073 } 02074 } 02075 else { 02076 blockarg = Qnil; 02077 } 02078 02079 vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self, 02080 0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0, 02081 th->cfp->sp, 1, 0); 02082 02083 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); 02084 02085 th->cfp++; 02086 return val; 02087 } 02088 02089 02090 /*-- 02091 * @brief on supplied all of optional, rest and post parameters. 02092 * @pre iseq is block style (not lambda style) 02093 */ 02094 static inline int 02095 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq, 02096 int argc, VALUE *argv) 02097 { 02098 rb_num_t opt_pc = 0; 02099 int i; 02100 const int m = iseq->argc; 02101 const int r = iseq->arg_rest; 02102 int len = iseq->arg_post_len; 02103 int start = iseq->arg_post_start; 02104 int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ 02105 int psize = rsize > len ? len : rsize; /* # of post arguments */ 02106 int osize = 0; /* # of opt arguments */ 02107 VALUE ary; 02108 02109 /* reserves arguments for post parameters */ 02110 rsize -= psize; 02111 02112 if (iseq->arg_opts) { 02113 const int opts = iseq->arg_opts - 1; 02114 if (rsize > opts) { 02115 osize = opts; 02116 opt_pc = iseq->arg_opt_table[opts]; 02117 } 02118 else { 02119 osize = rsize; 02120 opt_pc = iseq->arg_opt_table[rsize]; 02121 } 02122 } 02123 rsize -= osize; 02124 02125 if (0) { 02126 printf(" argc: %d\n", argc); 02127 printf(" len: %d\n", len); 02128 printf("start: %d\n", start); 02129 printf("rsize: %d\n", rsize); 02130 } 02131 02132 if (r == -1) { 02133 /* copy post argument */ 02134 MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); 02135 } 02136 else { 02137 ary = rb_ary_new4(rsize, &argv[r]); 02138 02139 /* copy post argument */ 02140 MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); 02141 argv[r] = ary; 02142 } 02143 02144 for (i=psize; i<len; i++) { 02145 argv[start + i] = Qnil; 02146 } 02147 02148 return (int)opt_pc; 02149 } 02150 02151 static inline int 02152 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, 02153 int orig_argc, VALUE *argv, 02154 const rb_block_t *blockptr) 02155 { 02156 int i; 02157 int argc = orig_argc; 02158 const int m = iseq->argc; 02159 VALUE ary, arg0; 02160 VALUE keyword_hash = Qnil; 02161 int opt_pc = 0; 02162 02163 th->mark_stack_len = argc; 02164 02165 /* 02166 * yield [1, 2] 02167 * => {|a|} => a = [1, 2] 02168 * => {|a, b|} => a, b = [1, 2] 02169 */ 02170 arg0 = argv[0]; 02171 if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ 02172 ((m + iseq->arg_post_len) > 0 || /* positional arguments exist */ 02173 iseq->arg_opts > 2 || /* multiple optional arguments exist */ 02174 iseq->arg_keyword != -1 || /* any keyword arguments */ 02175 0) && 02176 argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ 02177 th->mark_stack_len = argc = RARRAY_LENINT(ary); 02178 02179 CHECK_VM_STACK_OVERFLOW(th->cfp, argc); 02180 02181 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); 02182 } 02183 else { 02184 /* vm_push_frame current argv is at the top of sp because vm_invoke_block 02185 * set sp at the first element of argv. 02186 * Therefore when rb_check_array_type(arg0) called to_ary and called to_ary 02187 * or method_missing run vm_push_frame, it initializes local variables. 02188 * see also https://bugs.ruby-lang.org/issues/8484 02189 */ 02190 argv[0] = arg0; 02191 } 02192 02193 /* keyword argument */ 02194 if (iseq->arg_keyword != -1) { 02195 argc = vm_callee_setup_keyword_arg(iseq, argc, m, argv, &keyword_hash); 02196 } 02197 02198 for (i=argc; i<m; i++) { 02199 argv[i] = Qnil; 02200 } 02201 02202 if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { 02203 const int arg_size = iseq->arg_size; 02204 if (arg_size < argc) { 02205 /* 02206 * yield 1, 2 02207 * => {|a|} # truncate 02208 */ 02209 th->mark_stack_len = argc = arg_size; 02210 } 02211 } 02212 else { 02213 int r = iseq->arg_rest; 02214 02215 if (iseq->arg_post_len || 02216 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ 02217 opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); 02218 } 02219 else { 02220 if (argc < r) { 02221 /* yield 1 02222 * => {|a, b, *r|} 02223 */ 02224 for (i=argc; i<r; i++) { 02225 argv[i] = Qnil; 02226 } 02227 argv[r] = rb_ary_new(); 02228 } 02229 else { 02230 argv[r] = rb_ary_new4(argc-r, &argv[r]); 02231 } 02232 } 02233 02234 th->mark_stack_len = iseq->arg_size; 02235 } 02236 02237 /* keyword argument */ 02238 if (iseq->arg_keyword != -1) { 02239 argv[iseq->arg_keyword] = keyword_hash; 02240 } 02241 02242 /* {|&b|} */ 02243 if (iseq->arg_block != -1) { 02244 VALUE procval = Qnil; 02245 02246 if (blockptr) { 02247 if (blockptr->proc == 0) { 02248 procval = rb_vm_make_proc(th, blockptr, rb_cProc); 02249 } 02250 else { 02251 procval = blockptr->proc; 02252 } 02253 } 02254 02255 argv[iseq->arg_block] = procval; 02256 } 02257 02258 th->mark_stack_len = 0; 02259 return opt_pc; 02260 } 02261 02262 static inline int 02263 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, 02264 int argc, VALUE *argv, const rb_block_t *blockptr, int lambda) 02265 { 02266 if (0) { /* for debug */ 02267 printf(" argc: %d\n", argc); 02268 printf("iseq argc: %d\n", iseq->argc); 02269 printf("iseq opts: %d\n", iseq->arg_opts); 02270 printf("iseq rest: %d\n", iseq->arg_rest); 02271 printf("iseq post: %d\n", iseq->arg_post_len); 02272 printf("iseq blck: %d\n", iseq->arg_block); 02273 printf("iseq smpl: %d\n", iseq->arg_simple); 02274 printf(" lambda: %s\n", lambda ? "true" : "false"); 02275 } 02276 02277 if (lambda) { 02278 /* call as method */ 02279 rb_call_info_t ci_entry; 02280 ci_entry.flag = 0; 02281 ci_entry.argc = argc; 02282 ci_entry.blockptr = (rb_block_t *)blockptr; 02283 VM_CALLEE_SETUP_ARG(th, &ci_entry, iseq, argv, 1); 02284 return ci_entry.aux.opt_pc; 02285 } 02286 else { 02287 return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); 02288 } 02289 } 02290 02291 static VALUE 02292 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 02293 { 02294 const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp); 02295 rb_iseq_t *iseq; 02296 VALUE type = GET_ISEQ()->local_iseq->type; 02297 02298 if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) { 02299 rb_vm_localjump_error("no block given (yield)", Qnil, 0); 02300 } 02301 iseq = block->iseq; 02302 02303 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) { 02304 vm_caller_setup_args(th, GET_CFP(), ci); 02305 } 02306 02307 if (BUILTIN_TYPE(iseq) != T_NODE) { 02308 int opt_pc; 02309 const int arg_size = iseq->arg_size; 02310 VALUE * const rsp = GET_SP() - ci->argc; 02311 SET_SP(rsp); 02312 02313 CHECK_VM_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); 02314 opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, block_proc_is_lambda(block->proc)); 02315 02316 vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self, 02317 block->klass, 02318 VM_ENVVAL_PREV_EP_PTR(block->ep), 02319 iseq->iseq_encoded + opt_pc, 02320 rsp + arg_size, 02321 iseq->local_size - arg_size, 0); 02322 02323 return Qundef; 02324 } 02325 else { 02326 VALUE val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0); 02327 POPN(ci->argc); /* TODO: should put before C/yield? */ 02328 return val; 02329 } 02330 } 02331