|
Ruby
2.0.0p353(2013-11-22revision43784)
|
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 vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_method_entry_t*, VALUE); 00923 00924 static VALUE 00925 check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) 00926 { 00927 switch (type) { 00928 case VM_CHECKMATCH_TYPE_WHEN: 00929 return pattern; 00930 case VM_CHECKMATCH_TYPE_RESCUE: 00931 if (!rb_obj_is_kind_of(pattern, rb_cModule)) { 00932 rb_raise(rb_eTypeError, "class or module required for rescue clause"); 00933 } 00934 /* fall through */ 00935 case VM_CHECKMATCH_TYPE_CASE: { 00936 VALUE defined_class; 00937 rb_method_entry_t *me = rb_method_entry_with_refinements(CLASS_OF(pattern), idEqq, &defined_class); 00938 return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me, defined_class); 00939 } 00940 default: 00941 rb_bug("check_match: unreachable"); 00942 } 00943 } 00944 00945 00946 #if defined(_MSC_VER) && _MSC_VER < 1300 00947 #define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse; 00948 #else 00949 #define CHECK_CMP_NAN(a, b) /* do nothing */ 00950 #endif 00951 00952 static inline VALUE 00953 double_cmp_lt(double a, double b) 00954 { 00955 CHECK_CMP_NAN(a, b); 00956 return a < b ? Qtrue : Qfalse; 00957 } 00958 00959 static inline VALUE 00960 double_cmp_le(double a, double b) 00961 { 00962 CHECK_CMP_NAN(a, b); 00963 return a <= b ? Qtrue : Qfalse; 00964 } 00965 00966 static inline VALUE 00967 double_cmp_gt(double a, double b) 00968 { 00969 CHECK_CMP_NAN(a, b); 00970 return a > b ? Qtrue : Qfalse; 00971 } 00972 00973 static inline VALUE 00974 double_cmp_ge(double a, double b) 00975 { 00976 CHECK_CMP_NAN(a, b); 00977 return a >= b ? Qtrue : Qfalse; 00978 } 00979 00980 static VALUE * 00981 vm_base_ptr(rb_control_frame_t *cfp) 00982 { 00983 rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 00984 VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1; 00985 00986 if (cfp->iseq->type == ISEQ_TYPE_METHOD) { 00987 /* adjust `self' */ 00988 bp += 1; 00989 } 00990 00991 #if VM_DEBUG_BP_CHECK 00992 if (bp != cfp->bp_check) { 00993 fprintf(stderr, "bp_check: %ld, bp: %ld\n", 00994 (long)(cfp->bp_check - GET_THREAD()->stack), 00995 (long)(bp - GET_THREAD()->stack)); 00996 rb_bug("vm_base_ptr: unreachable"); 00997 } 00998 #endif 00999 01000 return bp; 01001 } 01002 01003 /* method call processes with call_info */ 01004 01005 static void 01006 vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01007 { 01008 #define SAVE_RESTORE_CI(expr, ci) do { \ 01009 int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \ 01010 expr; \ 01011 (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \ 01012 } while (0) 01013 01014 if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) { 01015 rb_proc_t *po; 01016 VALUE proc; 01017 01018 proc = *(--cfp->sp); 01019 01020 if (proc != Qnil) { 01021 if (!rb_obj_is_proc(proc)) { 01022 VALUE b; 01023 01024 SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci); 01025 01026 if (NIL_P(b) || !rb_obj_is_proc(b)) { 01027 rb_raise(rb_eTypeError, 01028 "wrong argument type %s (expected Proc)", 01029 rb_obj_classname(proc)); 01030 } 01031 proc = b; 01032 } 01033 GetProcPtr(proc, po); 01034 ci->blockptr = &po->block; 01035 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; 01036 } 01037 } 01038 else if (ci->blockiseq != 0) { /* likely */ 01039 ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); 01040 ci->blockptr->iseq = ci->blockiseq; 01041 ci->blockptr->proc = 0; 01042 } 01043 01044 /* expand top of stack? */ 01045 01046 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) { 01047 VALUE ary = *(cfp->sp - 1); 01048 VALUE *ptr; 01049 int i; 01050 VALUE tmp; 01051 01052 SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci); 01053 01054 if (NIL_P(tmp)) { 01055 /* do nothing */ 01056 } 01057 else { 01058 long len = RARRAY_LEN(tmp); 01059 ptr = RARRAY_PTR(tmp); 01060 cfp->sp -= 1; 01061 01062 CHECK_VM_STACK_OVERFLOW(cfp, len); 01063 01064 for (i = 0; i < len; i++) { 01065 *cfp->sp++ = ptr[i]; 01066 } 01067 ci->argc += i-1; 01068 } 01069 } 01070 } 01071 01072 static int 01073 separate_symbol(st_data_t key, st_data_t value, st_data_t arg) 01074 { 01075 VALUE *kwdhash = (VALUE *)arg; 01076 01077 if (!SYMBOL_P(key)) kwdhash++; 01078 if (!*kwdhash) *kwdhash = rb_hash_new(); 01079 rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value); 01080 return ST_CONTINUE; 01081 } 01082 01083 static VALUE 01084 extract_keywords(VALUE *orighash) 01085 { 01086 VALUE parthash[2] = {0, 0}; 01087 VALUE hash = *orighash; 01088 01089 if (RHASH_EMPTY_P(hash)) { 01090 *orighash = 0; 01091 return hash; 01092 } 01093 st_foreach(RHASH_TBL(hash), separate_symbol, (st_data_t)&parthash); 01094 *orighash = parthash[1]; 01095 return parthash[0]; 01096 } 01097 01098 static inline int 01099 vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd) 01100 { 01101 VALUE keyword_hash, orig_hash; 01102 int i, j; 01103 01104 if (argc > m && 01105 !NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) && 01106 (keyword_hash = extract_keywords(&orig_hash)) != 0) { 01107 if (!orig_hash) { 01108 argc--; 01109 } 01110 else { 01111 orig_argv[argc-1] = orig_hash; 01112 } 01113 if (iseq->arg_keyword_check) { 01114 for (i = j = 0; i < iseq->arg_keywords; i++) { 01115 if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++; 01116 } 01117 if (RHASH_TBL(keyword_hash)->num_entries > (unsigned int) j) { 01118 unknown_keyword_error(iseq, keyword_hash); 01119 } 01120 } 01121 } 01122 else { 01123 keyword_hash = rb_hash_new(); 01124 } 01125 01126 *kwd = keyword_hash; 01127 01128 return argc; 01129 } 01130 01131 static inline int 01132 vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *orig_argv) 01133 { 01134 const int m = iseq->argc; 01135 const int opts = iseq->arg_opts - (iseq->arg_opts > 0); 01136 const int min = m + iseq->arg_post_len; 01137 const int max = (iseq->arg_rest == -1) ? m + opts + iseq->arg_post_len : UNLIMITED_ARGUMENTS; 01138 const int orig_argc = ci->argc; 01139 int argc = orig_argc; 01140 VALUE *argv = orig_argv; 01141 VALUE keyword_hash = Qnil; 01142 rb_num_t opt_pc = 0; 01143 01144 th->mark_stack_len = argc + iseq->arg_size; 01145 01146 /* keyword argument */ 01147 if (iseq->arg_keyword != -1) { 01148 argc = vm_callee_setup_keyword_arg(iseq, argc, m, orig_argv, &keyword_hash); 01149 } 01150 01151 /* mandatory */ 01152 if ((argc < min) || (argc > max && max != UNLIMITED_ARGUMENTS)) { 01153 argument_error(iseq, argc, min, max); 01154 } 01155 01156 argv += m; 01157 argc -= m; 01158 01159 /* post arguments */ 01160 if (iseq->arg_post_len) { 01161 if (!(orig_argc < iseq->arg_post_start)) { 01162 VALUE *new_argv = ALLOCA_N(VALUE, argc); 01163 MEMCPY(new_argv, argv, VALUE, argc); 01164 argv = new_argv; 01165 } 01166 01167 MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len], 01168 VALUE, iseq->arg_post_len); 01169 } 01170 01171 /* opt arguments */ 01172 if (iseq->arg_opts) { 01173 if (argc > opts) { 01174 argc -= opts; 01175 argv += opts; 01176 opt_pc = iseq->arg_opt_table[opts]; /* no opt */ 01177 } 01178 else { 01179 int i; 01180 for (i = argc; i<opts; i++) { 01181 orig_argv[i + m] = Qnil; 01182 } 01183 opt_pc = iseq->arg_opt_table[argc]; 01184 argc = 0; 01185 } 01186 } 01187 01188 /* rest arguments */ 01189 if (iseq->arg_rest != -1) { 01190 orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv); 01191 argc = 0; 01192 } 01193 01194 /* keyword argument */ 01195 if (iseq->arg_keyword != -1) { 01196 orig_argv[iseq->arg_keyword] = keyword_hash; 01197 } 01198 01199 /* block arguments */ 01200 if (iseq->arg_block != -1) { 01201 VALUE blockval = Qnil; 01202 const rb_block_t *blockptr = ci->blockptr; 01203 01204 if (blockptr) { 01205 /* make Proc object */ 01206 if (blockptr->proc == 0) { 01207 rb_proc_t *proc; 01208 blockval = rb_vm_make_proc(th, blockptr, rb_cProc); 01209 GetProcPtr(blockval, proc); 01210 ci->blockptr = &proc->block; 01211 } 01212 else { 01213 blockval = blockptr->proc; 01214 } 01215 } 01216 01217 orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ 01218 } 01219 01220 th->mark_stack_len = 0; 01221 return (int)opt_pc; 01222 } 01223 01224 static VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01225 static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01226 static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01227 01228 #define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \ 01229 if (LIKELY((iseq)->arg_simple & 0x01)) { \ 01230 /* simple check */ \ 01231 if ((ci)->argc != (iseq)->argc) { \ 01232 argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \ 01233 } \ 01234 (ci)->aux.opt_pc = 0; \ 01235 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)); \ 01236 } \ 01237 else { \ 01238 (ci)->aux.opt_pc = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \ 01239 } 01240 01241 static VALUE 01242 vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01243 { 01244 VM_CALLEE_SETUP_ARG(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0); 01245 return vm_call_iseq_setup_2(th, cfp, ci); 01246 } 01247 01248 static VALUE 01249 vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01250 { 01251 if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) { 01252 return vm_call_iseq_setup_normal(th, cfp, ci); 01253 } 01254 else { 01255 return vm_call_iseq_setup_tailcall(th, cfp, ci); 01256 } 01257 } 01258 01259 static inline VALUE 01260 vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01261 { 01262 int i; 01263 VALUE *argv = cfp->sp - ci->argc; 01264 rb_iseq_t *iseq = ci->me->def->body.iseq; 01265 VALUE *sp = argv + iseq->arg_size; 01266 01267 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); 01268 01269 /* clear local variables */ 01270 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 01271 *sp++ = Qnil; 01272 } 01273 01274 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, 01275 VM_ENVVAL_BLOCK_PTR(ci->blockptr), 01276 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); 01277 01278 cfp->sp = argv - 1 /* recv */; 01279 return Qundef; 01280 } 01281 01282 static inline VALUE 01283 vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01284 { 01285 int i; 01286 VALUE *argv = cfp->sp - ci->argc; 01287 rb_iseq_t *iseq = ci->me->def->body.iseq; 01288 VALUE *src_argv = argv; 01289 VALUE *sp_orig, *sp; 01290 VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0; 01291 01292 cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */ 01293 01294 CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); 01295 RUBY_VM_CHECK_INTS(th); 01296 01297 sp_orig = sp = cfp->sp; 01298 01299 /* push self */ 01300 sp[0] = ci->recv; 01301 sp++; 01302 01303 /* copy arguments */ 01304 for (i=0; i < iseq->arg_size; i++) { 01305 *sp++ = src_argv[i]; 01306 } 01307 01308 /* clear local variables */ 01309 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 01310 *sp++ = Qnil; 01311 } 01312 01313 vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, 01314 ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), 01315 iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); 01316 01317 cfp->sp = sp_orig; 01318 return Qundef; 01319 } 01320 01321 static VALUE 01322 call_cfunc_m2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01323 { 01324 return (*func)(recv, rb_ary_new4(argc, argv)); 01325 } 01326 01327 static VALUE 01328 call_cfunc_m1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01329 { 01330 return (*func)(argc, argv, recv); 01331 } 01332 01333 static VALUE 01334 call_cfunc_0(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01335 { 01336 return (*func)(recv); 01337 } 01338 01339 static VALUE 01340 call_cfunc_1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01341 { 01342 return (*func)(recv, argv[0]); 01343 } 01344 01345 static VALUE 01346 call_cfunc_2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01347 { 01348 return (*func)(recv, argv[0], argv[1]); 01349 } 01350 01351 static VALUE 01352 call_cfunc_3(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01353 { 01354 return (*func)(recv, argv[0], argv[1], argv[2]); 01355 } 01356 01357 static VALUE 01358 call_cfunc_4(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01359 { 01360 return (*func)(recv, argv[0], argv[1], argv[2], argv[3]); 01361 } 01362 01363 static VALUE 01364 call_cfunc_5(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01365 { 01366 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]); 01367 } 01368 01369 static VALUE 01370 call_cfunc_6(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01371 { 01372 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); 01373 } 01374 01375 static VALUE 01376 call_cfunc_7(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01377 { 01378 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); 01379 } 01380 01381 static VALUE 01382 call_cfunc_8(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01383 { 01384 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); 01385 } 01386 01387 static VALUE 01388 call_cfunc_9(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01389 { 01390 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); 01391 } 01392 01393 static VALUE 01394 call_cfunc_10(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01395 { 01396 return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]); 01397 } 01398 01399 static VALUE 01400 call_cfunc_11(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01401 { 01402 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]); 01403 } 01404 01405 static VALUE 01406 call_cfunc_12(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01407 { 01408 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]); 01409 } 01410 01411 static VALUE 01412 call_cfunc_13(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01413 { 01414 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]); 01415 } 01416 01417 static VALUE 01418 call_cfunc_14(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01419 { 01420 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]); 01421 } 01422 01423 static VALUE 01424 call_cfunc_15(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv) 01425 { 01426 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]); 01427 } 01428 01429 #ifndef VM_PROFILE 01430 #define VM_PROFILE 0 01431 #endif 01432 01433 #if VM_PROFILE 01434 static int vm_profile_counter[4]; 01435 #define VM_PROFILE_UP(x) (vm_profile_counter[x]++) 01436 #define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result) 01437 static void vm_profile_show_result(void) 01438 { 01439 fprintf(stderr, "VM Profile results: \n"); 01440 fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]); 01441 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]); 01442 fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]); 01443 fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]); 01444 } 01445 #else 01446 #define VM_PROFILE_UP(x) 01447 #define VM_PROFILE_ATEXIT() 01448 #endif 01449 01450 static VALUE 01451 vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01452 { 01453 VALUE val; 01454 const rb_method_entry_t *me = ci->me; 01455 const rb_method_cfunc_t *cfunc = &me->def->body.cfunc; 01456 int len = cfunc->argc; 01457 01458 /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */ 01459 VALUE recv = ci->recv; 01460 VALUE defined_class = ci->defined_class; 01461 rb_block_t *blockptr = ci->blockptr; 01462 int argc = ci->argc; 01463 01464 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); 01465 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef); 01466 01467 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, 01468 VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me); 01469 01470 if (len >= 0) rb_check_arity(argc, len, len); 01471 01472 reg_cfp->sp -= argc + 1; 01473 VM_PROFILE_UP(0); 01474 val = (*cfunc->invoker)(cfunc->func, recv, argc, reg_cfp->sp + 1); 01475 01476 if (reg_cfp != th->cfp + 1) { 01477 rb_bug("vm_call_cfunc - cfp consistency error"); 01478 } 01479 01480 vm_pop_frame(th); 01481 01482 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); 01483 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); 01484 01485 return val; 01486 } 01487 01488 #if OPT_CALL_CFUNC_WITHOUT_FRAME 01489 static VALUE 01490 vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01491 { 01492 VALUE val; 01493 int argc = ci->argc; 01494 VALUE *argv = STACK_ADDR_FROM_TOP(argc); 01495 const rb_method_cfunc_t *cfunc = &ci->me->def->body.cfunc; 01496 01497 th->passed_ci = ci; 01498 reg_cfp->sp -= argc + 1; 01499 ci->aux.inc_sp = argc + 1; 01500 VM_PROFILE_UP(0); 01501 val = (*cfunc->invoker)(cfunc->func, ci, argv); 01502 01503 /* check */ 01504 if (reg_cfp == th->cfp) { /* no frame push */ 01505 if (UNLIKELY(th->passed_ci != ci)) { 01506 rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci); 01507 } 01508 th->passed_ci = 0; 01509 } 01510 else { 01511 if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) { 01512 rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1); 01513 } 01514 vm_pop_frame(th); 01515 VM_PROFILE_UP(1); 01516 } 01517 01518 return val; 01519 } 01520 01521 static VALUE 01522 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01523 { 01524 VALUE val; 01525 const rb_method_entry_t *me = ci->me; 01526 int len = me->def->body.cfunc.argc; 01527 VALUE recv = ci->recv; 01528 01529 if (len >= 0) rb_check_arity(ci->argc, len, len); 01530 01531 RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); 01532 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil); 01533 01534 if (!(ci->me->flag & NOEX_PROTECTED) && 01535 !(ci->flag & VM_CALL_ARGS_SPLAT)) { 01536 CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1); 01537 } 01538 val = vm_call_cfunc_latter(th, reg_cfp, ci); 01539 01540 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); 01541 RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); 01542 01543 return val; 01544 } 01545 01546 void 01547 vm_call_cfunc_push_frame(rb_thread_t *th) 01548 { 01549 rb_call_info_t *ci = th->passed_ci; 01550 const rb_method_entry_t *me = ci->me; 01551 th->passed_ci = 0; 01552 01553 vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, 01554 VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me); 01555 01556 if (ci->call != vm_call_general) { 01557 ci->call = vm_call_cfunc_with_frame; 01558 } 01559 } 01560 #else /* OPT_CALL_CFUNC_WITHOUT_FRAME */ 01561 static VALUE 01562 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01563 { 01564 return vm_call_cfunc_with_frame(th, reg_cfp, ci); 01565 } 01566 #endif 01567 01568 static VALUE 01569 vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01570 { 01571 VALUE val = vm_getivar(ci->recv, ci->me->def->body.attr.id, 0, ci, 1); 01572 cfp->sp -= 1; 01573 return val; 01574 } 01575 01576 static VALUE 01577 vm_call_attrset(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01578 { 01579 VALUE val = vm_setivar(ci->recv, ci->me->def->body.attr.id, *(cfp->sp - 1), 0, ci, 1); 01580 cfp->sp -= 2; 01581 return val; 01582 } 01583 01584 static inline VALUE 01585 vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv) 01586 { 01587 rb_proc_t *proc; 01588 VALUE val; 01589 01590 RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id); 01591 EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil); 01592 01593 /* control block frame */ 01594 th->passed_me = ci->me; 01595 GetProcPtr(ci->me->def->body.proc, proc); 01596 val = vm_invoke_proc(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr); 01597 01598 EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, ci->recv, ci->me->called_id, ci->me->klass, val); 01599 RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->me->klass, ci->me->called_id); 01600 01601 return val; 01602 } 01603 01604 static VALUE 01605 vm_call_bmethod(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01606 { 01607 VALUE *argv = ALLOCA_N(VALUE, ci->argc); 01608 MEMCPY(argv, cfp->sp - ci->argc, VALUE, ci->argc); 01609 cfp->sp += - ci->argc - 1; 01610 01611 return vm_call_bmethod_body(th, ci, argv); 01612 } 01613 01614 static 01615 #ifdef _MSC_VER 01616 __forceinline 01617 #else 01618 inline 01619 #endif 01620 VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); 01621 01622 static VALUE 01623 vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01624 { 01625 int i = ci->argc - 1; 01626 VALUE sym; 01627 rb_call_info_t ci_entry; 01628 01629 if (ci->argc == 0) { 01630 rb_raise(rb_eArgError, "no method name given"); 01631 } 01632 01633 ci_entry = *ci; /* copy ci entry */ 01634 ci = &ci_entry; 01635 01636 sym = TOPN(i); 01637 01638 if (SYMBOL_P(sym)) { 01639 ci->mid = SYM2ID(sym); 01640 } 01641 else if (!(ci->mid = rb_check_id(&sym))) { 01642 if (rb_method_basic_definition_p(CLASS_OF(ci->recv), idMethodMissing)) { 01643 VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i)); 01644 rb_exc_raise(exc); 01645 } 01646 ci->mid = rb_to_id(sym); 01647 } 01648 01649 /* shift arguments */ 01650 if (i > 0) { 01651 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); 01652 } 01653 ci->me = 01654 rb_method_entry_without_refinements(CLASS_OF(ci->recv), 01655 ci->mid, &ci->defined_class); 01656 ci->argc -= 1; 01657 DEC_SP(1); 01658 01659 ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; 01660 01661 return vm_call_method(th, reg_cfp, ci); 01662 } 01663 01664 static VALUE 01665 vm_call_opt_call(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01666 { 01667 rb_proc_t *proc; 01668 int argc = ci->argc; 01669 VALUE *argv = ALLOCA_N(VALUE, argc); 01670 GetProcPtr(ci->recv, proc); 01671 MEMCPY(argv, cfp->sp - argc, VALUE, argc); 01672 cfp->sp -= argc + 1; 01673 01674 return rb_vm_invoke_proc(th, proc, argc, argv, ci->blockptr); 01675 } 01676 01677 static VALUE 01678 vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01679 { 01680 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc); 01681 rb_call_info_t ci_entry; 01682 01683 ci_entry.flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; 01684 ci_entry.argc = ci->argc+1; 01685 ci_entry.mid = idMethodMissing; 01686 ci_entry.blockptr = ci->blockptr; 01687 ci_entry.recv = ci->recv; 01688 ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class); 01689 01690 /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */ 01691 CHECK_VM_STACK_OVERFLOW(reg_cfp, 1); 01692 if (ci->argc > 0) { 01693 MEMMOVE(argv+1, argv, VALUE, ci->argc); 01694 } 01695 argv[0] = ID2SYM(ci->mid); 01696 INC_SP(1); 01697 01698 th->method_missing_reason = ci->aux.missing_reason; 01699 return vm_call_method(th, reg_cfp, &ci_entry); 01700 } 01701 01702 static inline VALUE 01703 find_refinement(VALUE refinements, VALUE klass) 01704 { 01705 if (NIL_P(refinements)) { 01706 return Qnil; 01707 } 01708 return rb_hash_lookup(refinements, klass); 01709 } 01710 01711 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2); 01712 static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci); 01713 01714 static rb_control_frame_t * 01715 current_method_entry(rb_thread_t *th, rb_control_frame_t *cfp) 01716 { 01717 rb_control_frame_t *top_cfp = cfp; 01718 01719 if (cfp->iseq && cfp->iseq->type == ISEQ_TYPE_BLOCK) { 01720 rb_iseq_t *local_iseq = cfp->iseq->local_iseq; 01721 do { 01722 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01723 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 01724 /* TODO: orphan block */ 01725 return top_cfp; 01726 } 01727 } while (cfp->iseq != local_iseq); 01728 } 01729 return cfp; 01730 } 01731 01732 static 01733 #ifdef _MSC_VER 01734 __forceinline 01735 #else 01736 inline 01737 #endif 01738 VALUE 01739 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) 01740 { 01741 int enable_fastpath = 1; 01742 rb_call_info_t ci_temp; 01743 01744 start_method_dispatch: 01745 if (ci->me != 0) { 01746 if ((ci->me->flag == 0)) { 01747 VALUE klass; 01748 01749 normal_method_dispatch: 01750 switch (ci->me->def->type) { 01751 case VM_METHOD_TYPE_ISEQ:{ 01752 CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath); 01753 return vm_call_iseq_setup(th, cfp, ci); 01754 } 01755 case VM_METHOD_TYPE_NOTIMPLEMENTED: 01756 case VM_METHOD_TYPE_CFUNC: 01757 CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath); 01758 return vm_call_cfunc(th, cfp, ci); 01759 case VM_METHOD_TYPE_ATTRSET:{ 01760 rb_check_arity(ci->argc, 1, 1); 01761 ci->aux.index = 0; 01762 CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); 01763 return vm_call_attrset(th, cfp, ci); 01764 } 01765 case VM_METHOD_TYPE_IVAR:{ 01766 rb_check_arity(ci->argc, 0, 0); 01767 ci->aux.index = 0; 01768 CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); 01769 return vm_call_ivar(th, cfp, ci); 01770 } 01771 case VM_METHOD_TYPE_MISSING:{ 01772 ci->aux.missing_reason = 0; 01773 CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath); 01774 return vm_call_method_missing(th, cfp, ci); 01775 } 01776 case VM_METHOD_TYPE_BMETHOD:{ 01777 CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath); 01778 return vm_call_bmethod(th, cfp, ci); 01779 } 01780 case VM_METHOD_TYPE_ZSUPER:{ 01781 klass = ci->me->klass; 01782 klass = RCLASS_ORIGIN(klass); 01783 zsuper_method_dispatch: 01784 klass = RCLASS_SUPER(klass); 01785 ci_temp = *ci; 01786 ci = &ci_temp; 01787 01788 ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); 01789 01790 if (ci->me != 0) { 01791 goto normal_method_dispatch; 01792 } 01793 else { 01794 goto start_method_dispatch; 01795 } 01796 } 01797 case VM_METHOD_TYPE_OPTIMIZED:{ 01798 switch (ci->me->def->body.optimize_type) { 01799 case OPTIMIZED_METHOD_TYPE_SEND: 01800 CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath); 01801 return vm_call_opt_send(th, cfp, ci); 01802 case OPTIMIZED_METHOD_TYPE_CALL: 01803 CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath); 01804 return vm_call_opt_call(th, cfp, ci); 01805 default: 01806 rb_bug("vm_call_method: unsupported optimized method type (%d)", 01807 ci->me->def->body.optimize_type); 01808 } 01809 break; 01810 } 01811 case VM_METHOD_TYPE_UNDEF: 01812 break; 01813 case VM_METHOD_TYPE_REFINED:{ 01814 NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep); 01815 VALUE refinements = cref ? cref->nd_refinements : Qnil; 01816 VALUE refinement, defined_class; 01817 rb_method_entry_t *me; 01818 01819 refinement = find_refinement(refinements, 01820 ci->defined_class); 01821 if (NIL_P(refinement)) { 01822 goto no_refinement_dispatch; 01823 } 01824 me = rb_method_entry(refinement, ci->mid, &defined_class); 01825 if (me) { 01826 if (ci->call == vm_call_super_method) { 01827 rb_control_frame_t *top_cfp = current_method_entry(th, cfp); 01828 if (top_cfp->me && 01829 rb_method_definition_eq(me->def, top_cfp->me->def)) { 01830 goto no_refinement_dispatch; 01831 } 01832 } 01833 ci->me = me; 01834 ci->defined_class = defined_class; 01835 if (me->def->type != VM_METHOD_TYPE_REFINED) { 01836 goto normal_method_dispatch; 01837 } 01838 } 01839 01840 no_refinement_dispatch: 01841 if (ci->me->def->body.orig_me) { 01842 ci->me = ci->me->def->body.orig_me; 01843 if (UNDEFINED_METHOD_ENTRY_P(ci->me)) { 01844 ci->me = 0; 01845 goto start_method_dispatch; 01846 } 01847 else { 01848 goto normal_method_dispatch; 01849 } 01850 } 01851 else { 01852 klass = ci->me->klass; 01853 goto zsuper_method_dispatch; 01854 } 01855 } 01856 } 01857 rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type); 01858 } 01859 else { 01860 int noex_safe; 01861 if (!(ci->flag & VM_CALL_FCALL) && (ci->me->flag & NOEX_MASK) & NOEX_PRIVATE) { 01862 int stat = NOEX_PRIVATE; 01863 01864 if (ci->flag & VM_CALL_VCALL) { 01865 stat |= NOEX_VCALL; 01866 } 01867 ci->aux.missing_reason = stat; 01868 CI_SET_FASTPATH(ci, vm_call_method_missing, 1); 01869 return vm_call_method_missing(th, cfp, ci); 01870 } 01871 else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) { 01872 enable_fastpath = 0; 01873 if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) { 01874 ci->aux.missing_reason = NOEX_PROTECTED; 01875 return vm_call_method_missing(th, cfp, ci); 01876 } 01877 else { 01878 goto normal_method_dispatch; 01879 } 01880 } 01881 else if ((noex_safe = NOEX_SAFE(ci->me->flag)) > th->safe_level && (noex_safe > 2)) { 01882 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(ci->mid)); 01883 } 01884 else { 01885 goto normal_method_dispatch; 01886 } 01887 } 01888 } 01889 else { 01890 /* method missing */ 01891 int stat = 0; 01892 if (ci->flag & VM_CALL_VCALL) { 01893 stat |= NOEX_VCALL; 01894 } 01895 if (ci->flag & VM_CALL_SUPER) { 01896 stat |= NOEX_SUPER; 01897 } 01898 if (ci->mid == idMethodMissing) { 01899 rb_control_frame_t *reg_cfp = cfp; 01900 VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc); 01901 rb_raise_method_missing(th, ci->argc, argv, ci->recv, stat); 01902 } 01903 else { 01904 ci->aux.missing_reason = stat; 01905 CI_SET_FASTPATH(ci, vm_call_method_missing, 1); 01906 return vm_call_method_missing(th, cfp, ci); 01907 } 01908 } 01909 01910 rb_bug("vm_call_method: unreachable"); 01911 } 01912 01913 static VALUE 01914 vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01915 { 01916 return vm_call_method(th, reg_cfp, ci); 01917 } 01918 01919 static VALUE 01920 vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01921 { 01922 return vm_call_method(th, reg_cfp, ci); 01923 } 01924 01925 /* super */ 01926 01927 static inline VALUE 01928 vm_search_normal_superclass(VALUE klass) 01929 { 01930 if (BUILTIN_TYPE(klass) == T_ICLASS && 01931 FL_TEST(RBASIC(klass)->klass, RMODULE_IS_REFINEMENT)) { 01932 klass = RBASIC(klass)->klass; 01933 } 01934 klass = RCLASS_ORIGIN(klass); 01935 return RCLASS_SUPER(klass); 01936 } 01937 01938 static void 01939 vm_super_outside(void) 01940 { 01941 rb_raise(rb_eNoMethodError, "super called outside of method"); 01942 } 01943 01944 static int 01945 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci) 01946 { 01947 while (iseq && !iseq->klass) { 01948 iseq = iseq->parent_iseq; 01949 } 01950 01951 if (iseq == 0) { 01952 return -1; 01953 } 01954 01955 ci->mid = iseq->defined_method_id; 01956 01957 if (iseq != iseq->local_iseq) { 01958 /* defined by Module#define_method() */ 01959 rb_control_frame_t *lcfp = GET_CFP(); 01960 01961 if (!sigval) { 01962 /* zsuper */ 01963 return -2; 01964 } 01965 01966 while (lcfp->iseq != iseq) { 01967 rb_thread_t *th = GET_THREAD(); 01968 VALUE *tep = VM_EP_PREV_EP(lcfp->ep); 01969 while (1) { 01970 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); 01971 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) { 01972 return -1; 01973 } 01974 if (lcfp->ep == tep) { 01975 break; 01976 } 01977 } 01978 } 01979 01980 /* temporary measure for [Bug #2420] [Bug #3136] */ 01981 if (!lcfp->me) { 01982 return -1; 01983 } 01984 01985 ci->mid = lcfp->me->def->original_id; 01986 ci->klass = vm_search_normal_superclass(lcfp->klass); 01987 } 01988 else { 01989 ci->klass = vm_search_normal_superclass(reg_cfp->klass); 01990 } 01991 01992 return 0; 01993 } 01994 01995 static void 01996 vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 01997 { 01998 VALUE current_defined_class; 01999 rb_iseq_t *iseq = GET_ISEQ(); 02000 VALUE sigval = TOPN(ci->argc); 02001 02002 current_defined_class = GET_CFP()->klass; 02003 if (NIL_P(current_defined_class)) { 02004 vm_super_outside(); 02005 } 02006 02007 if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) { 02008 current_defined_class = RCLASS_REFINED_CLASS(current_defined_class); 02009 } 02010 02011 if (!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) && 02012 !rb_obj_is_kind_of(ci->recv, current_defined_class)) { 02013 VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ? 02014 RBASIC(current_defined_class)->klass : current_defined_class; 02015 02016 rb_raise(rb_eTypeError, 02017 "self has wrong type to call super in this context: " 02018 "%s (expected %s)", 02019 rb_obj_classname(ci->recv), rb_class2name(m)); 02020 } 02021 02022 switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) { 02023 case -1: 02024 vm_super_outside(); 02025 case -2: 02026 rb_raise(rb_eRuntimeError, 02027 "implicit argument passing of super from method defined" 02028 " by define_method() is not supported." 02029 " Specify all arguments explicitly."); 02030 } 02031 02032 /* TODO: use inline cache */ 02033 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); 02034 ci->call = vm_call_super_method; 02035 02036 while (iseq && !iseq->klass) { 02037 iseq = iseq->parent_iseq; 02038 } 02039 02040 if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) { 02041 ci->klass = RCLASS_SUPER(ci->defined_class); 02042 ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); 02043 } 02044 } 02045 02046 /* yield */ 02047 02048 static inline int 02049 block_proc_is_lambda(const VALUE procval) 02050 { 02051 rb_proc_t *proc; 02052 02053 if (procval) { 02054 GetProcPtr(procval, proc); 02055 return proc->is_lambda; 02056 } 02057 else { 02058 return 0; 02059 } 02060 } 02061 02062 static inline VALUE 02063 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, 02064 VALUE self, int argc, const VALUE *argv, 02065 const rb_block_t *blockargptr) 02066 { 02067 NODE *ifunc = (NODE *) block->iseq; 02068 VALUE val, arg, blockarg; 02069 int lambda = block_proc_is_lambda(block->proc); 02070 02071 if (lambda) { 02072 arg = rb_ary_new4(argc, argv); 02073 } 02074 else if (argc == 0) { 02075 arg = Qnil; 02076 } 02077 else { 02078 arg = argv[0]; 02079 } 02080 02081 if (blockargptr) { 02082 if (blockargptr->proc) { 02083 blockarg = blockargptr->proc; 02084 } 02085 else { 02086 blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); 02087 } 02088 } 02089 else { 02090 blockarg = Qnil; 02091 } 02092 02093 vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self, 02094 0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0, 02095 th->cfp->sp, 1, 0); 02096 02097 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); 02098 02099 th->cfp++; 02100 return val; 02101 } 02102 02103 02104 /*-- 02105 * @brief on supplied all of optional, rest and post parameters. 02106 * @pre iseq is block style (not lambda style) 02107 */ 02108 static inline int 02109 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq, 02110 int argc, VALUE *argv) 02111 { 02112 rb_num_t opt_pc = 0; 02113 int i; 02114 const int m = iseq->argc; 02115 const int r = iseq->arg_rest; 02116 int len = iseq->arg_post_len; 02117 int start = iseq->arg_post_start; 02118 int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ 02119 int psize = rsize > len ? len : rsize; /* # of post arguments */ 02120 int osize = 0; /* # of opt arguments */ 02121 VALUE ary; 02122 02123 /* reserves arguments for post parameters */ 02124 rsize -= psize; 02125 02126 if (iseq->arg_opts) { 02127 const int opts = iseq->arg_opts - 1; 02128 if (rsize > opts) { 02129 osize = opts; 02130 opt_pc = iseq->arg_opt_table[opts]; 02131 } 02132 else { 02133 osize = rsize; 02134 opt_pc = iseq->arg_opt_table[rsize]; 02135 } 02136 } 02137 rsize -= osize; 02138 02139 if (0) { 02140 printf(" argc: %d\n", argc); 02141 printf(" len: %d\n", len); 02142 printf("start: %d\n", start); 02143 printf("rsize: %d\n", rsize); 02144 } 02145 02146 if (r == -1) { 02147 /* copy post argument */ 02148 MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); 02149 } 02150 else { 02151 ary = rb_ary_new4(rsize, &argv[r]); 02152 02153 /* copy post argument */ 02154 MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); 02155 argv[r] = ary; 02156 } 02157 02158 for (i=psize; i<len; i++) { 02159 argv[start + i] = Qnil; 02160 } 02161 02162 return (int)opt_pc; 02163 } 02164 02165 static inline int 02166 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, 02167 int orig_argc, VALUE *argv, 02168 const rb_block_t *blockptr) 02169 { 02170 int i; 02171 int argc = orig_argc; 02172 const int m = iseq->argc; 02173 VALUE ary, arg0; 02174 VALUE keyword_hash = Qnil; 02175 int opt_pc = 0; 02176 02177 th->mark_stack_len = argc; 02178 02179 /* 02180 * yield [1, 2] 02181 * => {|a|} => a = [1, 2] 02182 * => {|a, b|} => a, b = [1, 2] 02183 */ 02184 arg0 = argv[0]; 02185 if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ 02186 ((m + iseq->arg_post_len) > 0 || /* positional arguments exist */ 02187 iseq->arg_opts > 2 || /* multiple optional arguments exist */ 02188 iseq->arg_keyword != -1 || /* any keyword arguments */ 02189 0) && 02190 argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ 02191 th->mark_stack_len = argc = RARRAY_LENINT(ary); 02192 02193 CHECK_VM_STACK_OVERFLOW(th->cfp, argc); 02194 02195 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); 02196 } 02197 else { 02198 /* vm_push_frame current argv is at the top of sp because vm_invoke_block 02199 * set sp at the first element of argv. 02200 * Therefore when rb_check_array_type(arg0) called to_ary and called to_ary 02201 * or method_missing run vm_push_frame, it initializes local variables. 02202 * see also https://bugs.ruby-lang.org/issues/8484 02203 */ 02204 argv[0] = arg0; 02205 } 02206 02207 /* keyword argument */ 02208 if (iseq->arg_keyword != -1) { 02209 argc = vm_callee_setup_keyword_arg(iseq, argc, m, argv, &keyword_hash); 02210 } 02211 02212 for (i=argc; i<m; i++) { 02213 argv[i] = Qnil; 02214 } 02215 02216 if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { 02217 const int arg_size = iseq->arg_size; 02218 if (arg_size < argc) { 02219 /* 02220 * yield 1, 2 02221 * => {|a|} # truncate 02222 */ 02223 th->mark_stack_len = argc = arg_size; 02224 } 02225 } 02226 else { 02227 int r = iseq->arg_rest; 02228 02229 if (iseq->arg_post_len || 02230 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ 02231 opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); 02232 } 02233 else { 02234 if (argc < r) { 02235 /* yield 1 02236 * => {|a, b, *r|} 02237 */ 02238 for (i=argc; i<r; i++) { 02239 argv[i] = Qnil; 02240 } 02241 argv[r] = rb_ary_new(); 02242 } 02243 else { 02244 argv[r] = rb_ary_new4(argc-r, &argv[r]); 02245 } 02246 } 02247 02248 th->mark_stack_len = iseq->arg_size; 02249 } 02250 02251 /* keyword argument */ 02252 if (iseq->arg_keyword != -1) { 02253 argv[iseq->arg_keyword] = keyword_hash; 02254 } 02255 02256 /* {|&b|} */ 02257 if (iseq->arg_block != -1) { 02258 VALUE procval = Qnil; 02259 02260 if (blockptr) { 02261 if (blockptr->proc == 0) { 02262 procval = rb_vm_make_proc(th, blockptr, rb_cProc); 02263 } 02264 else { 02265 procval = blockptr->proc; 02266 } 02267 } 02268 02269 argv[iseq->arg_block] = procval; 02270 } 02271 02272 th->mark_stack_len = 0; 02273 return opt_pc; 02274 } 02275 02276 static inline int 02277 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, 02278 int argc, VALUE *argv, const rb_block_t *blockptr, int lambda) 02279 { 02280 if (0) { /* for debug */ 02281 printf(" argc: %d\n", argc); 02282 printf("iseq argc: %d\n", iseq->argc); 02283 printf("iseq opts: %d\n", iseq->arg_opts); 02284 printf("iseq rest: %d\n", iseq->arg_rest); 02285 printf("iseq post: %d\n", iseq->arg_post_len); 02286 printf("iseq blck: %d\n", iseq->arg_block); 02287 printf("iseq smpl: %d\n", iseq->arg_simple); 02288 printf(" lambda: %s\n", lambda ? "true" : "false"); 02289 } 02290 02291 if (lambda) { 02292 /* call as method */ 02293 rb_call_info_t ci_entry; 02294 ci_entry.flag = 0; 02295 ci_entry.argc = argc; 02296 ci_entry.blockptr = (rb_block_t *)blockptr; 02297 VM_CALLEE_SETUP_ARG(th, &ci_entry, iseq, argv, 1); 02298 return ci_entry.aux.opt_pc; 02299 } 02300 else { 02301 return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); 02302 } 02303 } 02304 02305 static VALUE 02306 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) 02307 { 02308 const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp); 02309 rb_iseq_t *iseq; 02310 VALUE type = GET_ISEQ()->local_iseq->type; 02311 02312 if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) { 02313 rb_vm_localjump_error("no block given (yield)", Qnil, 0); 02314 } 02315 iseq = block->iseq; 02316 02317 if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) { 02318 vm_caller_setup_args(th, GET_CFP(), ci); 02319 } 02320 02321 if (BUILTIN_TYPE(iseq) != T_NODE) { 02322 int opt_pc; 02323 const int arg_size = iseq->arg_size; 02324 VALUE * const rsp = GET_SP() - ci->argc; 02325 SET_SP(rsp); 02326 02327 CHECK_VM_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); 02328 opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, block_proc_is_lambda(block->proc)); 02329 02330 vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self, 02331 block->klass, 02332 VM_ENVVAL_PREV_EP_PTR(block->ep), 02333 iseq->iseq_encoded + opt_pc, 02334 rsp + arg_size, 02335 iseq->local_size - arg_size, 0); 02336 02337 return Qundef; 02338 } 02339 else { 02340 VALUE val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0); 02341 POPN(ci->argc); /* TODO: should put before C/yield? */ 02342 return val; 02343 } 02344 } 02345
1.7.6.1