vm_insnhelper.c

Go to the documentation of this file.
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               size_t stack_max)
00045 {
00046     rb_control_frame_t *const cfp = th->cfp - 1;
00047     int i;
00048 
00049     /* check stack overflow */
00050     CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + (int)stack_max);
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     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 /* self */, Qnil /* klass */, Qnil /* specval*/,
00135                       iseq->iseq_encoded, th->cfp->sp, 0 /* local_size */, 0 /* me */, 0 /* stack_max */);
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 /* svar */
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     /* TODO: why cref->nd_next is 1? */
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         /* in current lexical scope */
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         /* search self */
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 { /* call_info */
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  /* USE_IC_FOR_IVAR */
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; /* inline cache hit */
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             /* fall through */
00571         }
00572     }
00573 #endif  /* USE_IC_FOR_IVAR */
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                     /* lambda{... break ...} */
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                 /* check orphan and get dfp */
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                                 /* lambda {class A; ... return ...; end} */
00703                                 ep = cfp->ep;
00704                                 goto valid_return;
00705                             }
00706 
00707                             while (target_lep != tep) {
00708                                 if (cfp->ep == tep) {
00709                                     /* in lambda */
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         /* continue throw */
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             /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
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         /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
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         /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
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         /* cache hit! */
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         /* fall through */
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           /* fallback to funcall (e.g. method_missing) */
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) /* do nothing */
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         /* adjust `self' */
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 /* method call processes with call_info */
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; /* save */ \
01007     expr; \
01008     (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \
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) { /* likely */
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     /* expand top of stack? */
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             /* do nothing */
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     /* keyword argument */
01122     if (iseq->arg_keyword != -1) {
01123         argc = vm_callee_setup_keyword_arg(th, iseq, argc, min, orig_argv, &keyword_hash);
01124     }
01125 
01126     /* mandatory */
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     /* post arguments */
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     /* opt arguments */
01147     if (iseq->arg_opts) {
01148         if (argc > opts) {
01149             argc -= opts;
01150             argv += opts;
01151             opt_pc = iseq->arg_opt_table[opts]; /* no opt */
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     /* rest arguments */
01164     if (iseq->arg_rest != -1) {
01165         orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv);
01166         argc = 0;
01167     }
01168 
01169     /* keyword argument */
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     /* block arguments */
01180     if (iseq->arg_block != -1) {
01181         VALUE blockval = Qnil;
01182         const rb_block_t *blockptr = ci->blockptr;
01183 
01184         if (blockptr) {
01185             /* make Proc object */
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; /* Proc or nil */
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         /* simple check */
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) && /* argc may differ for each calls */
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     /* clear local variables (arg_size...local_size) */
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 /* recv */;
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); /* pop cf */
01281 
01282     RUBY_VM_CHECK_INTS(th);
01283 
01284     sp_orig = sp = cfp->sp;
01285 
01286     /* push self */
01287     sp[0] = ci->recv;
01288     sp++;
01289 
01290     /* copy arguments */
01291     for (i=0; i < iseq->arg_size; i++) {
01292         *sp++ = src_argv[i];
01293     }
01294 
01295     /* clear local variables */
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     /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
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     /* check */
01519     if (reg_cfp == th->cfp) { /* no frame push */
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 /* OPT_CALL_CFUNC_WITHOUT_FRAME */
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     /* control block frame */
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; /* copy ci entry */
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     /* shift arguments */
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     /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
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                 /* TODO: orphan block */
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         /* method missing */
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 /* super */
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         /* defined by Module#define_method() */
01969         rb_control_frame_t *lcfp = GET_CFP();
01970 
01971         if (!sigval) {
01972             /* zsuper */
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         /* temporary measure for [Bug #2420] [Bug #3136] */
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 && /* bound UnboundMethod */
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         /* bound instance method of module */
02045         ci->aux.missing_reason = NOEX_SUPER;
02046         CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
02047         return;
02048     }
02049 
02050     /* TODO: use inline cache */
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 /* yield */
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  * @brief on supplied all of optional, rest and post parameters.
02124  * @pre iseq is block style (not lambda style)
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;    /* # of arguments which did not consumed yet */
02137     int psize = rsize > len ? len : rsize;  /* # of post arguments */
02138     int osize = 0;  /* # of opt arguments */
02139     VALUE ary;
02140 
02141     /* reserves arguments for post parameters */
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         /* copy post argument */
02166         MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize);
02167     }
02168     else {
02169         ary = rb_ary_new4(rsize, &argv[r]);
02170 
02171         /* copy post argument */
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      * yield [1, 2]
02200      *  => {|a|} => a = [1, 2]
02201      *  => {|a, b|} => a, b = [1, 2]
02202      */
02203     arg0 = argv[0];
02204     if (!(iseq->arg_simple & 0x02) &&                           /* exclude {|a|} */
02205         (min > 0 ||                                             /* positional arguments exist */
02206          iseq->arg_opts > 2 ||                                  /* multiple optional arguments exist */
02207          iseq->arg_keyword != -1 ||                             /* any keyword arguments */
02208          0) &&
02209         argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */
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         /* vm_push_frame current argv is at the top of sp because vm_invoke_block
02218          * set sp at the first element of argv.
02219          * Therefore when rb_check_array_type(arg0) called to_ary and called to_ary
02220          * or method_missing run vm_push_frame, it initializes local variables.
02221          * see also https://bugs.ruby-lang.org/issues/8484
02222          */
02223         argv[0] = arg0;
02224     }
02225 
02226     /* keyword argument */
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              * yield 1, 2
02240              * => {|a|} # truncate
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) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
02250             opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv);
02251         }
02252         else {
02253             if (argc < r) {
02254                 /* yield 1
02255                  * => {|a, b, *r|}
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     /* keyword argument */
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     /* {|&b|} */
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) { /* for debug */
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         /* call as method */
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); /* TODO: should put before C/yield? */
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 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7