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