Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# vm_insnhelper.c

Go to the documentation of this file.

    00001 /**********************************************************************
    00002
    00003   vm_insnhelper.c - instruction helper functions.
    00004
    00005   $Author: yugui $
    00006
    00007   Copyright (C) 2007 Koichi Sasada
    00008
    00009 **********************************************************************/
    00010
    00011 /* finish iseq array */
    00012 #include "insns.inc"
    00013 #include <math.h>
    00014
    00015 /* control stack frame */
    00016
    00017 #ifndef INLINE
    00018 #define INLINE inline
    00019 #endif
    00020
    00021 static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
    00022
    00023 static inline rb_control_frame_t *
    00024 vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
    00025               VALUE type, VALUE self, VALUE specval,
    00026               const VALUE *pc, VALUE *sp, VALUE *lfp,
    00027               int local_size)
    00028 {
    00029     rb_control_frame_t * const cfp = th->cfp - 1;
    00030     int i;
    00031
    00032     if ((void *)(sp + local_size) >= (void *)cfp) {
    00033         rb_exc_raise(sysstack_error);
    00034     }
    00035     th->cfp = cfp;
    00036     /* setup vm value stack */
    00037
    00038     /* nil initialize */
    00039     for (i=0; i < local_size; i++) {
    00040         *sp = Qnil;
    00041         sp++;
    00042     }
    00043
    00044     /* set special val */
    00045     *sp = GC_GUARDED_PTR(specval);
    00046
    00047     if (lfp == 0) {
    00048         lfp = sp;
    00049     }
    00050
    00051     /* setup vm control frame stack */
    00052
    00053     cfp->pc = (VALUE *)pc;
    00054     cfp->sp = sp + 1;
    00055     cfp->bp = sp + 1;
    00056     cfp->iseq = (rb_iseq_t *) iseq;
    00057     cfp->flag = type;
    00058     cfp->self = self;
    00059     cfp->lfp = lfp;
    00060     cfp->dfp = sp;
    00061     cfp->block_iseq = 0;
    00062     cfp->proc = 0;
    00063     cfp->me = 0;
    00064
    00065 #define COLLECT_PROFILE 0
    00066 #if COLLECT_PROFILE
    00067     cfp->prof_time_self = clock();
    00068     cfp->prof_time_chld = 0;
    00069 #endif
    00070
    00071     if (VMDEBUG == 2) {
    00072         SDR();
    00073     }
    00074
    00075     return cfp;
    00076 }
    00077
    00078 static inline void
    00079 vm_pop_frame(rb_thread_t *th)
    00080 {
    00081 #if COLLECT_PROFILE
    00082     rb_control_frame_t *cfp = th->cfp;
    00083
    00084     if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
    00085         VALUE current_time = clock();
    00086         rb_control_frame_t *cfp = th->cfp;
    00087         cfp->prof_time_self = current_time - cfp->prof_time_self;
    00088         (cfp+1)->prof_time_chld += cfp->prof_time_self;
    00089
    00090         cfp->iseq->profile.count++;
    00091         cfp->iseq->profile.time_cumu = cfp->prof_time_self;
    00092         cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld;
    00093     }
    00094     else if (0 /* c method? */) {
    00095
    00096     }
    00097 #endif
    00098     th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
    00099
    00100     if (VMDEBUG == 2) {
    00101         SDR();
    00102     }
    00103 }
    00104
    00105 /* method dispatch */
    00106
    00107 NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc));
    00108 static void
    00109 argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc)
    00110 {
    00111     VALUE mesg = rb_sprintf("wrong number of arguments (%d for %d)", miss_argc, correct_argc);
    00112     VALUE exc = rb_exc_new3(rb_eArgError, mesg);
    00113     VALUE bt = rb_make_backtrace();
    00114     VALUE err_line = 0;
    00115
    00116     if (iseq) {
    00117         int line_no = 1;
    00118
    00119         if (iseq->insn_info_size) {
    00120             line_no = iseq->insn_info_table[0].line_no;
    00121         }
    00122
    00123         err_line = rb_sprintf("%s:%d:in `%s'",
    00124                               RSTRING_PTR(iseq->filename),
    00125                               line_no, RSTRING_PTR(iseq->name));
    00126         rb_funcall(bt, rb_intern("unshift"), 1, err_line);
    00127     }
    00128
    00129     rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
    00130     rb_exc_raise(exc);
    00131 }
    00132
    00133 #define VM_CALLEE_SETUP_ARG(ret, th, iseq, orig_argc, orig_argv, block) \
    00134     if (LIKELY(iseq->arg_simple & 0x01)) { \
    00135         /* simple check */ \
    00136         if (orig_argc != iseq->argc) { \
    00137             argument_error(iseq, orig_argc, iseq->argc); \
    00138         } \
    00139         ret = 0; \
    00140     } \
    00141     else { \
    00142         ret = vm_callee_setup_arg_complex(th, iseq, orig_argc, orig_argv, block); \
    00143     }
    00144
    00145 static inline int
    00146 vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq,
    00147                             int orig_argc, VALUE * orig_argv,
    00148                             const rb_block_t **block)
    00149 {
    00150     const int m = iseq->argc;
    00151     int argc = orig_argc;
    00152     VALUE *argv = orig_argv;
    00153     rb_num_t opt_pc = 0;
    00154
    00155     th->mark_stack_len = argc + iseq->arg_size;
    00156
    00157     /* mandatory */
    00158     if (argc < (m + iseq->arg_post_len)) { /* check with post arg */
    00159         argument_error(iseq, argc, m + iseq->arg_post_len);
    00160     }
    00161
    00162     argv += m;
    00163     argc -= m;
    00164
    00165     /* post arguments */
    00166     if (iseq->arg_post_len) {
    00167         if (!(orig_argc < iseq->arg_post_start)) {
    00168             VALUE *new_argv = ALLOCA_N(VALUE, argc);
    00169             MEMCPY(new_argv, argv, VALUE, argc);
    00170             argv = new_argv;
    00171         }
    00172
    00173         MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len],
    00174                VALUE, iseq->arg_post_len);
    00175     }
    00176
    00177     /* opt arguments */
    00178     if (iseq->arg_opts) {
    00179         const int opts = iseq->arg_opts - 1 /* no opt */;
    00180
    00181         if (iseq->arg_rest == -1 && argc > opts) {
    00182             argument_error(iseq, orig_argc, m + opts + iseq->arg_post_len);
    00183         }
    00184
    00185         if (argc > opts) {
    00186             argc -= opts;
    00187             argv += opts;
    00188             opt_pc = iseq->arg_opt_table[opts]; /* no opt */
    00189         }
    00190         else {
    00191             int i;
    00192             for (i = argc; i<opts; i++) {
    00193                 orig_argv[i + m] = Qnil;
    00194             }
    00195             opt_pc = iseq->arg_opt_table[argc];
    00196             argc = 0;
    00197         }
    00198     }
    00199
    00200     /* rest arguments */
    00201     if (iseq->arg_rest != -1) {
    00202         orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv);
    00203         argc = 0;
    00204     }
    00205
    00206     /* block arguments */
    00207     if (block && iseq->arg_block != -1) {
    00208         VALUE blockval = Qnil;
    00209         const rb_block_t *blockptr = *block;
    00210
    00211         if (argc != 0) {
    00212             argument_error(iseq, orig_argc, m + iseq->arg_post_len);
    00213         }
    00214
    00215         if (blockptr) {
    00216             /* make Proc object */
    00217             if (blockptr->proc == 0) {
    00218                 rb_proc_t *proc;
    00219                 blockval = rb_vm_make_proc(th, blockptr, rb_cProc);
    00220                 GetProcPtr(blockval, proc);
    00221                 *block = &proc->block;
    00222             }
    00223             else {
    00224                 blockval = blockptr->proc;
    00225             }
    00226         }
    00227
    00228         orig_argv[iseq->arg_block] = blockval; /* Proc or nil */
    00229     }
    00230
    00231     th->mark_stack_len = 0;
    00232     return (int)opt_pc;
    00233 }
    00234
    00235 static inline int
    00236 caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, VALUE flag,
    00237                   int argc, rb_iseq_t *blockiseq, rb_block_t **block)
    00238 {
    00239     rb_block_t *blockptr = 0;
    00240
    00241     if (block) {
    00242         if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
    00243             rb_proc_t *po;
    00244             VALUE proc;
    00245
    00246             proc = *(--cfp->sp);
    00247
    00248             if (proc != Qnil) {
    00249                 if (!rb_obj_is_proc(proc)) {
    00250                     VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
    00251                     if (NIL_P(b) || !rb_obj_is_proc(b)) {
    00252                         rb_raise(rb_eTypeError,
    00253                                  "wrong argument type %s (expected Proc)",
    00254                                  rb_obj_classname(proc));
    00255                     }
    00256                     proc = b;
    00257                 }
    00258                 GetProcPtr(proc, po);
    00259                 blockptr = &po->block;
    00260                 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
    00261                 *block = blockptr;
    00262             }
    00263         }
    00264         else if (blockiseq) {
    00265             blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
    00266             blockptr->iseq = blockiseq;
    00267             blockptr->proc = 0;
    00268             *block = blockptr;
    00269         }
    00270     }
    00271
    00272     /* expand top of stack? */
    00273     if (flag & VM_CALL_ARGS_SPLAT_BIT) {
    00274         VALUE ary = *(cfp->sp - 1);
    00275         VALUE *ptr;
    00276         int i;
    00277         VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
    00278
    00279         if (NIL_P(tmp)) {
    00280             /* do nothing */
    00281         }
    00282         else {
    00283             long len = RARRAY_LEN(tmp);
    00284             ptr = RARRAY_PTR(tmp);
    00285             cfp->sp -= 1;
    00286
    00287             CHECK_STACK_OVERFLOW(cfp, len);
    00288
    00289             for (i = 0; i < len; i++) {
    00290                 *cfp->sp++ = ptr[i];
    00291             }
    00292             argc += i-1;
    00293         }
    00294     }
    00295
    00296     return argc;
    00297 }
    00298
    00299 static inline VALUE
    00300 call_cfunc(VALUE (*func)(), VALUE recv,
    00301            int len, int argc, const VALUE *argv)
    00302 {
    00303     /* printf("len: %d, argc: %d\n", len, argc); */
    00304
    00305     if (len >= 0 && argc != len) {
    00306         rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
    00307                  argc, len);
    00308     }
    00309
    00310     switch (len) {
    00311       case -2:
    00312         return (*func) (recv, rb_ary_new4(argc, argv));
    00313         break;
    00314       case -1:
    00315         return (*func) (argc, argv, recv);
    00316         break;
    00317       case 0:
    00318         return (*func) (recv);
    00319         break;
    00320       case 1:
    00321         return (*func) (recv, argv[0]);
    00322         break;
    00323       case 2:
    00324         return (*func) (recv, argv[0], argv[1]);
    00325         break;
    00326       case 3:
    00327         return (*func) (recv, argv[0], argv[1], argv[2]);
    00328         break;
    00329       case 4:
    00330         return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
    00331         break;
    00332       case 5:
    00333         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
    00334         break;
    00335       case 6:
    00336         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00337                         argv[5]);
    00338         break;
    00339       case 7:
    00340         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00341                         argv[5], argv[6]);
    00342         break;
    00343       case 8:
    00344         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00345                         argv[5], argv[6], argv[7]);
    00346         break;
    00347       case 9:
    00348         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00349                         argv[5], argv[6], argv[7], argv[8]);
    00350         break;
    00351       case 10:
    00352         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00353                         argv[5], argv[6], argv[7], argv[8], argv[9]);
    00354         break;
    00355       case 11:
    00356         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00357                         argv[5], argv[6], argv[7], argv[8], argv[9],
    00358                         argv[10]);
    00359         break;
    00360       case 12:
    00361         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00362                         argv[5], argv[6], argv[7], argv[8], argv[9],
    00363                         argv[10], argv[11]);
    00364         break;
    00365       case 13:
    00366         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00367                         argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
    00368                         argv[11], argv[12]);
    00369         break;
    00370       case 14:
    00371         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00372                         argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
    00373                         argv[11], argv[12], argv[13]);
    00374         break;
    00375       case 15:
    00376         return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
    00377                         argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
    00378                         argv[11], argv[12], argv[13], argv[14]);
    00379         break;
    00380       default:
    00381         rb_raise(rb_eArgError, "too many arguments(%d)", len);
    00382         return Qundef; /* not reached */
    00383     }
    00384 }
    00385
    00386 static inline VALUE
    00387 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
    00388               int num, VALUE recv, const rb_block_t *blockptr,
    00389               const rb_method_entry_t *me)
    00390 {
    00391     VALUE val = 0;
    00392     const rb_method_definition_t *def = me->def;
    00393     rb_control_frame_t *cfp;
    00394
    00395     EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
    00396
    00397     cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
    00398                         recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
    00399     cfp->me = me;
    00400     reg_cfp->sp -= num + 1;
    00401
    00402     val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1);
    00403
    00404     if (reg_cfp != th->cfp + 1) {
    00405         rb_bug("cfp consistency error - send");
    00406     }
    00407
    00408     vm_pop_frame(th);
    00409
    00410     EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
    00411
    00412     return val;
    00413 }
    00414
    00415 static inline VALUE
    00416 vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
    00417                 const rb_block_t *blockptr, const rb_method_entry_t *me)
    00418 {
    00419     rb_proc_t *proc;
    00420     VALUE val;
    00421
    00422     /* control block frame */
    00423     th->passed_me = me;
    00424
    00425     GetProcPtr(me->def->body.proc, proc);
    00426     val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
    00427     return val;
    00428 }
    00429
    00430 static inline void
    00431 vm_method_missing_args(rb_thread_t *th, VALUE *argv,
    00432                        int num, const rb_block_t *blockptr, int opt)
    00433 {
    00434     rb_control_frame_t * const reg_cfp = th->cfp;
    00435     MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
    00436     th->method_missing_reason = opt;
    00437     th->passed_block = blockptr;
    00438     POPN(num + 1);
    00439 }
    00440
    00441 static inline VALUE
    00442 vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
    00443                   int num, const rb_block_t *blockptr, int opt)
    00444 {
    00445     VALUE *argv = ALLOCA_N(VALUE, num + 1);
    00446     vm_method_missing_args(th, argv, num, blockptr, opt);
    00447     argv[0] = ID2SYM(id);
    00448     return rb_funcall2(recv, idMethodMissing, num + 1, argv);
    00449 }
    00450
    00451 static inline void
    00452 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
    00453                 VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
    00454                 const rb_method_entry_t *me)
    00455 {
    00456     int opt_pc, i;
    00457     VALUE *sp, *rsp = cfp->sp - argc;
    00458     rb_iseq_t *iseq = me->def->body.iseq;
    00459
    00460     VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr);
    00461
    00462     /* stack overflow check */
    00463     CHECK_STACK_OVERFLOW(cfp, iseq->stack_max);
    00464
    00465     sp = rsp + iseq->arg_size;
    00466
    00467     if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) {
    00468         if (0) printf("local_size: %d, arg_size: %d\n",
    00469                       iseq->local_size, iseq->arg_size);
    00470
    00471         /* clear local variables */
    00472         for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
    00473             *sp++ = Qnil;
    00474         }
    00475
    00476         vm_push_frame(th, iseq,
    00477                       VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
    00478                       iseq->iseq_encoded + opt_pc, sp, 0, 0);
    00479
    00480         cfp->sp = rsp - 1 /* recv */;
    00481     }
    00482     else {
    00483         VALUE *p_rsp;
    00484         th->cfp++; /* pop cf */
    00485         p_rsp = th->cfp->sp;
    00486
    00487         /* copy arguments */
    00488         for (i=0; i < (sp - rsp); i++) {
    00489             p_rsp[i] = rsp[i];
    00490         }
    00491
    00492         sp -= rsp - p_rsp;
    00493
    00494         /* clear local variables */
    00495         for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
    00496             *sp++ = Qnil;
    00497         }
    00498
    00499         vm_push_frame(th, iseq,
    00500                       VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
    00501                       iseq->iseq_encoded + opt_pc, sp, 0, 0);
    00502     }
    00503 }
    00504
    00505 static inline VALUE
    00506 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
    00507                int num, const rb_block_t *blockptr, VALUE flag,
    00508                ID id, const rb_method_entry_t *me, VALUE recv)
    00509 {
    00510     VALUE val;
    00511
    00512   start_method_dispatch:
    00513
    00514     if (me != 0) {
    00515         if ((me->flag == 0)) {
    00516           normal_method_dispatch:
    00517             switch (me->def->type) {
    00518               case VM_METHOD_TYPE_ISEQ:{
    00519                 vm_setup_method(th, cfp, recv, num, blockptr, flag, me);
    00520                 return Qundef;
    00521               }
    00522               case VM_METHOD_TYPE_NOTIMPLEMENTED:
    00523               case VM_METHOD_TYPE_CFUNC:{
    00524                 val = vm_call_cfunc(th, cfp, num, recv, blockptr, me);
    00525                 break;
    00526               }
    00527               case VM_METHOD_TYPE_ATTRSET:{
    00528                 if (num != 1) {
    00529                     rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num);
    00530                 }
    00531                 val = rb_ivar_set(recv, me->def->body.attr.id, *(cfp->sp - 1));
    00532                 cfp->sp -= 2;
    00533                 break;
    00534               }
    00535               case VM_METHOD_TYPE_IVAR:{
    00536                 if (num != 0) {
    00537                     rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num);
    00538                 }
    00539                 val = rb_attr_get(recv, me->def->body.attr.id);
    00540                 cfp->sp -= 1;
    00541                 break;
    00542               }
    00543               case VM_METHOD_TYPE_MISSING:{
    00544                 VALUE *argv = ALLOCA_N(VALUE, num+1);
    00545                 argv[0] = ID2SYM(me->def->original_id);
    00546                 MEMCPY(argv+1, cfp->sp - num, VALUE, num);
    00547                 cfp->sp += - num - 1;
    00548                 val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv);
    00549                 break;
    00550               }
    00551               case VM_METHOD_TYPE_BMETHOD:{
    00552                 VALUE *argv = ALLOCA_N(VALUE, num);
    00553                 MEMCPY(argv, cfp->sp - num, VALUE, num);
    00554                 cfp->sp += - num - 1;
    00555                 val = vm_call_bmethod(th, recv, num, argv, blockptr, me);
    00556                 break;
    00557               }
    00558               case VM_METHOD_TYPE_ZSUPER:{
    00559                 VALUE klass = RCLASS_SUPER(me->klass);
    00560                 me = rb_method_entry(klass, id);
    00561
    00562                 if (me != 0) {
    00563                     goto normal_method_dispatch;
    00564                 }
    00565                 else {
    00566                     goto start_method_dispatch;
    00567                 }
    00568               }
    00569               case VM_METHOD_TYPE_OPTIMIZED:{
    00570                 switch (me->def->body.optimize_type) {
    00571                   case OPTIMIZED_METHOD_TYPE_SEND: {
    00572                     rb_control_frame_t *reg_cfp = cfp;
    00573                     rb_num_t i = num - 1;
    00574                     VALUE sym;
    00575
    00576                     if (num == 0) {
    00577                         rb_raise(rb_eArgError, "no method name given");
    00578                     }
    00579
    00580                     sym = TOPN(i);
    00581                     id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
    00582                     /* shift arguments */
    00583                     if (i > 0) {
    00584                         MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
    00585                     }
    00586                     me = rb_method_entry(CLASS_OF(recv), id);
    00587                     num -= 1;
    00588                     DEC_SP(1);
    00589                     flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
    00590
    00591                     goto start_method_dispatch;
    00592                   }
    00593                   case OPTIMIZED_METHOD_TYPE_CALL: {
    00594                     rb_proc_t *proc;
    00595                     int argc = num;
    00596                     VALUE *argv = ALLOCA_N(VALUE, num);
    00597                     GetProcPtr(recv, proc);
    00598                     MEMCPY(argv, cfp->sp - num, VALUE, num);
    00599                     cfp->sp -= num + 1;
    00600
    00601                     val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr);
    00602                     break;
    00603                   }
    00604                   default:
    00605                     rb_bug("eval_invoke_method: unsupported optimized method type (%d)",
    00606                            me->def->body.optimize_type);
    00607                 }
    00608                 break;
    00609               }
    00610               default:{
    00611                 rb_bug("eval_invoke_method: unsupported method type (%d)", me->def->type);
    00612                 break;
    00613               }
    00614             }
    00615         }
    00616         else {
    00617             int noex_safe;
    00618
    00619             if (!(flag & VM_CALL_FCALL_BIT) &&
    00620                 (me->flag & NOEX_MASK) & NOEX_PRIVATE) {
    00621                 int stat = NOEX_PRIVATE;
    00622
    00623                 if (flag & VM_CALL_VCALL_BIT) {
    00624                     stat |= NOEX_VCALL;
    00625                 }
    00626                 val = vm_method_missing(th, id, recv, num, blockptr, stat);
    00627             }
    00628             else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
    00629                 VALUE defined_class = me->klass;
    00630
    00631                 if (TYPE(defined_class) == T_ICLASS) {
    00632                     defined_class = RBASIC(defined_class)->klass;
    00633                 }
    00634
    00635                 if (!rb_obj_is_kind_of(cfp->self, defined_class)) {
    00636                     val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED);
    00637                 }
    00638                 else {
    00639                     goto normal_method_dispatch;
    00640                 }
    00641             }
    00642             else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level &&
    00643                      (noex_safe > 2)) {
    00644                 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id));
    00645             }
    00646             else {
    00647                 goto normal_method_dispatch;
    00648             }
    00649         }
    00650     }
    00651     else {
    00652         /* method missing */
    00653         int stat = 0;
    00654         if (flag & VM_CALL_VCALL_BIT) {
    00655             stat |= NOEX_VCALL;
    00656         }
    00657         if (flag & VM_CALL_SUPER_BIT) {
    00658             stat |= NOEX_SUPER;
    00659         }
    00660         if (id == idMethodMissing) {
    00661             VALUE *argv = ALLOCA_N(VALUE, num);
    00662             vm_method_missing_args(th, argv, num - 1, 0, stat);
    00663             rb_raise_method_missing(th, num, argv, recv, stat);
    00664         }
    00665         else {
    00666             val = vm_method_missing(th, id, recv, num, blockptr, stat);
    00667         }
    00668     }
    00669
    00670     RUBY_VM_CHECK_INTS();
    00671     return val;
    00672 }
    00673
    00674 /* yield */
    00675
    00676 static inline int
    00677 block_proc_is_lambda(const VALUE procval)
    00678 {
    00679     rb_proc_t *proc;
    00680
    00681     if (procval) {
    00682         GetProcPtr(procval, proc);
    00683         return proc->is_lambda;
    00684     }
    00685     else {
    00686         return 0;
    00687     }
    00688 }
    00689
    00690 static inline VALUE
    00691 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
    00692                     VALUE self, int argc, const VALUE *argv,
    00693                     const rb_block_t *blockargptr)
    00694 {
    00695     NODE *ifunc = (NODE *) block->iseq;
    00696     VALUE val, arg, blockarg;
    00697     int lambda = block_proc_is_lambda(block->proc);
    00698
    00699     if (lambda) {
    00700         arg = rb_ary_new4(argc, argv);
    00701     }
    00702     else if (argc == 0) {
    00703         arg = Qnil;
    00704     }
    00705     else {
    00706         arg = argv[0];
    00707     }
    00708
    00709     if (blockargptr) {
    00710         if (blockargptr->proc) {
    00711             blockarg = blockargptr->proc;
    00712         }
    00713         else {
    00714             blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc);
    00715         }
    00716     }
    00717     else {
    00718         blockarg = Qnil;
    00719     }
    00720
    00721     vm_push_frame(th, 0, VM_FRAME_MAGIC_IFUNC,
    00722                   self, (VALUE)block->dfp,
    00723                   0, th->cfp->sp, block->lfp, 1);
    00724
    00725     if (blockargptr) {
    00726         th->cfp->lfp[0] = GC_GUARDED_PTR((VALUE)blockargptr);
    00727     }
    00728     val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
    00729
    00730     th->cfp++;
    00731     return val;
    00732 }
    00733
    00734
    00735 /*--
    00736  * @brief on supplied all of optional, rest and post parameters.
    00737  * @pre iseq is block style (not lambda style)
    00738  */
    00739 static inline int
    00740 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq,
    00741                                   int argc, VALUE *argv)
    00742 {
    00743     rb_num_t opt_pc = 0;
    00744     int i;
    00745     const int m = iseq->argc;
    00746     const int r = iseq->arg_rest;
    00747     int len = iseq->arg_post_len;
    00748     int start = iseq->arg_post_start;
    00749     int rsize = argc > m ? argc - m : 0;    /* # of arguments which did not consumed yet */
    00750     int psize = rsize > len ? len : rsize;  /* # of post arguments */
    00751     int osize = 0;  /* # of opt arguments */
    00752     VALUE ary;
    00753
    00754     /* reserves arguments for post parameters */
    00755     rsize -= psize;
    00756
    00757     if (iseq->arg_opts) {
    00758         const int opts = iseq->arg_opts - 1;
    00759         if (rsize > opts) {
    00760             osize = opts;
    00761             opt_pc = iseq->arg_opt_table[opts];
    00762         }
    00763         else {
    00764             osize = rsize;
    00765             opt_pc = iseq->arg_opt_table[rsize];
    00766         }
    00767     }
    00768     rsize -= osize;
    00769
    00770     if (0) {
    00771         printf(" argc: %d\n", argc);
    00772         printf("  len: %d\n", len);
    00773         printf("start: %d\n", start);
    00774         printf("rsize: %d\n", rsize);
    00775     }
    00776
    00777     if (r == -1) {
    00778         /* copy post argument */
    00779         MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize);
    00780     }
    00781     else {
    00782         ary = rb_ary_new4(rsize, &argv[r]);
    00783
    00784         /* copy post argument */
    00785         MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize);
    00786         argv[r] = ary;
    00787     }
    00788
    00789     for (i=psize; i<len; i++) {
    00790         argv[start + i] = Qnil;
    00791     }
    00792
    00793     return (int)opt_pc;
    00794 }
    00795
    00796 static inline int
    00797 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq,
    00798                           int orig_argc, VALUE *argv,
    00799                           const rb_block_t *blockptr)
    00800 {
    00801     int i;
    00802     int argc = orig_argc;
    00803     const int m = iseq->argc;
    00804     VALUE ary, arg0;
    00805     int opt_pc = 0;
    00806
    00807     th->mark_stack_len = argc;
    00808
    00809     /*
    00810      * yield [1, 2]
    00811      *  => {|a|} => a = [1, 2]
    00812      *  => {|a, b|} => a, b = [1, 2]
    00813      */
    00814     arg0 = argv[0];
    00815     if (!(iseq->arg_simple & 0x02) &&          /* exclude {|a|} */
    00816             (m + iseq->arg_post_len) > 0 &&    /* this process is meaningful */
    00817             argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */
    00818         th->mark_stack_len = argc = RARRAY_LENINT(ary);
    00819
    00820         CHECK_STACK_OVERFLOW(th->cfp, argc);
    00821
    00822         MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc);
    00823     }
    00824     else {
    00825         argv[0] = arg0;
    00826     }
    00827
    00828     for (i=argc; i<m; i++) {
    00829         argv[i] = Qnil;
    00830     }
    00831
    00832     if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
    00833         const int arg_size = iseq->arg_size;
    00834         if (arg_size < argc) {
    00835             /*
    00836              * yield 1, 2
    00837              * => {|a|} # truncate
    00838              */
    00839             th->mark_stack_len = argc = arg_size;
    00840         }
    00841     }
    00842     else {
    00843         int r = iseq->arg_rest;
    00844
    00845         if (iseq->arg_post_len ||
    00846                 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
    00847             opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv);
    00848         }
    00849         else {
    00850             if (argc < r) {
    00851                 /* yield 1
    00852                  * => {|a, b, *r|}
    00853                  */
    00854                 for (i=argc; i<r; i++) {
    00855                     argv[i] = Qnil;
    00856                 }
    00857                 argv[r] = rb_ary_new();
    00858             }
    00859             else {
    00860                 argv[r] = rb_ary_new4(argc-r, &argv[r]);
    00861             }
    00862         }
    00863
    00864         th->mark_stack_len = iseq->arg_size;
    00865     }
    00866
    00867     /* {|&b|} */
    00868     if (iseq->arg_block != -1) {
    00869         VALUE procval = Qnil;
    00870
    00871         if (blockptr) {
    00872             if (blockptr->proc == 0) {
    00873                 procval = rb_vm_make_proc(th, blockptr, rb_cProc);
    00874             }
    00875             else {
    00876                 procval = blockptr->proc;
    00877             }
    00878         }
    00879
    00880         argv[iseq->arg_block] = procval;
    00881     }
    00882
    00883     th->mark_stack_len = 0;
    00884     return opt_pc;
    00885 }
    00886
    00887 static inline int
    00888 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
    00889                     int argc, VALUE *argv,
    00890                     const rb_block_t *blockptr, int lambda)
    00891 {
    00892     if (0) { /* for debug */
    00893         printf("     argc: %d\n", argc);
    00894         printf("iseq argc: %d\n", iseq->argc);
    00895         printf("iseq opts: %d\n", iseq->arg_opts);
    00896         printf("iseq rest: %d\n", iseq->arg_rest);
    00897         printf("iseq post: %d\n", iseq->arg_post_len);
    00898         printf("iseq blck: %d\n", iseq->arg_block);
    00899         printf("iseq smpl: %d\n", iseq->arg_simple);
    00900         printf("   lambda: %s\n", lambda ? "true" : "false");
    00901     }
    00902
    00903     if (lambda) {
    00904         /* call as method */
    00905         int opt_pc;
    00906         VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, argv, &blockptr);
    00907         return opt_pc;
    00908     }
    00909     else {
    00910         return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr);
    00911     }
    00912 }
    00913
    00914 static VALUE
    00915 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag)
    00916 {
    00917     const rb_block_t *block = GET_BLOCK_PTR();
    00918     rb_iseq_t *iseq;
    00919     int argc = (int)num;
    00920     VALUE type = GET_ISEQ()->local_iseq->type;
    00921
    00922     if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
    00923         rb_vm_localjump_error("no block given (yield)", Qnil, 0);
    00924     }
    00925     iseq = block->iseq;
    00926
    00927     argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0);
    00928
    00929     if (BUILTIN_TYPE(iseq) != T_NODE) {
    00930         int opt_pc;
    00931         const int arg_size = iseq->arg_size;
    00932         VALUE * const rsp = GET_SP() - argc;
    00933         SET_SP(rsp);
    00934
    00935         CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max);
    00936         opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0,
    00937                                      block_proc_is_lambda(block->proc));
    00938
    00939         vm_push_frame(th, iseq,
    00940                       VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
    00941                       iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
    00942                       iseq->local_size - arg_size);
    00943
    00944         return Qundef;
    00945     }
    00946     else {
    00947         VALUE val = vm_yield_with_cfunc(th, block, block->self, argc, STACK_ADDR_FROM_TOP(argc), 0);
    00948         POPN(argc); /* TODO: should put before C/yield? */
    00949         return val;
    00950     }
    00951 }
    00952
    00953 /* svar */
    00954
    00955 static inline NODE *
    00956 lfp_svar_place(rb_thread_t *th, VALUE *lfp)
    00957 {
    00958     VALUE *svar;
    00959
    00960     if (lfp && th->local_lfp != lfp) {
    00961         svar = &lfp[-1];
    00962     }
    00963     else {
    00964         svar = &th->local_svar;
    00965     }
    00966     if (NIL_P(*svar)) {
    00967         *svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil);
    00968     }
    00969     return (NODE *)*svar;
    00970 }
    00971
    00972 static VALUE
    00973 lfp_svar_get(rb_thread_t *th, VALUE *lfp, VALUE key)
    00974 {
    00975     NODE *svar = lfp_svar_place(th, lfp);
    00976
    00977     switch (key) {
    00978       case 0:
    00979         return svar->u1.value;
    00980       case 1:
    00981         return svar->u2.value;
    00982       default: {
    00983         const VALUE hash = svar->u3.value;
    00984
    00985         if (hash == Qnil) {
    00986             return Qnil;
    00987         }
    00988         else {
    00989             return rb_hash_lookup(hash, key);
    00990         }
    00991       }
    00992     }
    00993 }
    00994
    00995 static void
    00996 lfp_svar_set(rb_thread_t *th, VALUE *lfp, VALUE key, VALUE val)
    00997 {
    00998     NODE *svar = lfp_svar_place(th, lfp);
    00999
    01000     switch (key) {
    01001       case 0:
    01002         svar->u1.value = val;
    01003         return;
    01004       case 1:
    01005         svar->u2.value = val;
    01006         return;
    01007       default: {
    01008         VALUE hash = svar->u3.value;
    01009
    01010         if (hash == Qnil) {
    01011             svar->u3.value = hash = rb_hash_new();
    01012         }
    01013         rb_hash_aset(hash, key, val);
    01014       }
    01015     }
    01016 }
    01017
    01018 static inline VALUE
    01019 vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type)
    01020 {
    01021     VALUE val;
    01022
    01023     if (type == 0) {
    01024         VALUE k = key;
    01025         if (FIXNUM_P(key)) {
    01026             k = FIX2INT(key);
    01027         }
    01028         val = lfp_svar_get(th, lfp, k);
    01029     }
    01030     else {
    01031         VALUE backref = lfp_svar_get(th, lfp, 1);
    01032
    01033         if (type & 0x01) {
    01034             switch (type >> 1) {
    01035               case '&':
    01036                 val = rb_reg_last_match(backref);
    01037                 break;
    01038               case '`':
    01039                 val = rb_reg_match_pre(backref);
    01040                 break;
    01041               case '\'':
    01042                 val = rb_reg_match_post(backref);
    01043                 break;
    01044               case '+':
    01045                 val = rb_reg_match_last(backref);
    01046                 break;
    01047               default:
    01048                 rb_bug("unexpected back-ref");
    01049             }
    01050         }
    01051         else {
    01052             val = rb_reg_nth_match((int)(type >> 1), backref);
    01053         }
    01054     }
    01055     return val;
    01056 }
    01057
    01058 static NODE *
    01059 vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
    01060 {
    01061     while (1) {
    01062         if (lfp == dfp) {
    01063             return iseq->cref_stack;
    01064         }
    01065         else if (dfp[-1] != Qnil) {
    01066             return (NODE *)dfp[-1];
    01067         }
    01068         dfp = GET_PREV_DFP(dfp);
    01069     }
    01070 }
    01071
    01072 static NODE *
    01073 vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
    01074 {
    01075     NODE *cref = vm_get_cref0(iseq, lfp, dfp);
    01076
    01077     if (cref == 0) {
    01078         rb_bug("vm_get_cref: unreachable");
    01079     }
    01080     return cref;
    01081 }
    01082
    01083 static NODE *
    01084 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
    01085 {
    01086     rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
    01087     NODE *cref = NEW_BLOCK(klass);
    01088     cref->nd_file = 0;
    01089     cref->nd_visi = noex;
    01090
    01091     if (blockptr) {
    01092         cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->lfp, blockptr->dfp);
    01093     }
    01094     else if (cfp) {
    01095         cref->nd_next = vm_get_cref0(cfp->iseq, cfp->lfp, cfp->dfp);
    01096     }
    01097
    01098     return cref;
    01099 }
    01100
    01101 static inline VALUE
    01102 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
    01103 {
    01104     NODE *cref = vm_get_cref(iseq, lfp, dfp);
    01105     VALUE klass = Qundef;
    01106
    01107     while (cref) {
    01108         if ((klass = cref->nd_clss) != 0) {
    01109             break;
    01110         }
    01111         cref = cref->nd_next;
    01112     }
    01113
    01114     return klass;
    01115 }
    01116
    01117 static inline VALUE
    01118 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
    01119 {
    01120     NODE *cref = vm_get_cref(iseq, lfp, dfp);
    01121     VALUE klass = Qundef;
    01122
    01123     while (cref) {
    01124         if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) &&
    01125             (klass = cref->nd_clss) != 0) {
    01126             break;
    01127         }
    01128         cref = cref->nd_next;
    01129     }
    01130
    01131     return klass;
    01132 }
    01133
    01134 static inline void
    01135 vm_check_if_namespace(VALUE klass)
    01136 {
    01137     switch (TYPE(klass)) {
    01138       case T_CLASS:
    01139       case T_MODULE:
    01140         break;
    01141       default:
    01142         rb_raise(rb_eTypeError, "%s is not a class/module",
    01143                  RSTRING_PTR(rb_inspect(klass)));
    01144     }
    01145 }
    01146
    01147 static inline VALUE
    01148 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
    01149                 VALUE orig_klass, ID id, int is_defined)
    01150 {
    01151     VALUE val;
    01152
    01153     if (orig_klass == Qnil) {
    01154         /* in current lexical scope */
    01155         const NODE *cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp);
    01156         const NODE *root_cref = NULL;
    01157         VALUE klass = orig_klass;
    01158
    01159         while (cref && cref->nd_next) {
    01160             if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL)) {
    01161                 klass = cref->nd_clss;
    01162                 if (root_cref == NULL)
    01163                     root_cref = cref;
    01164             }
    01165             cref = cref->nd_next;
    01166
    01167             if (!NIL_P(klass)) {
    01168                 VALUE am = 0;
    01169               search_continue:
    01170                 if (RCLASS_IV_TBL(klass) &&
    01171                     st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
    01172                     if (val == Qundef) {
    01173                         if (am == klass) break;
    01174                         am = klass;
    01175                         rb_autoload_load(klass, id);
    01176                         goto search_continue;
    01177                     }
    01178                     else {
    01179                         if (is_defined) {
    01180                             return 1;
    01181                         }
    01182                         else {
    01183                             return val;
    01184                         }
    01185                     }
    01186                 }
    01187             }
    01188         }
    01189
    01190         /* search self */
    01191         if (root_cref && !NIL_P(root_cref->nd_clss)) {
    01192             klass = root_cref->nd_clss;
    01193         }
    01194         else {
    01195             klass = CLASS_OF(th->cfp->self);
    01196         }
    01197
    01198         if (is_defined) {
    01199             return rb_const_defined(klass, id);
    01200         }
    01201         else {
    01202             return rb_const_get(klass, id);
    01203         }
    01204     }
    01205     else {
    01206         vm_check_if_namespace(orig_klass);
    01207         if (is_defined) {
    01208             return rb_const_defined_from(orig_klass, id);
    01209         }
    01210         else {
    01211             return rb_const_get_from(orig_klass, id);
    01212         }
    01213     }
    01214 }
    01215
    01216 static inline VALUE
    01217 vm_get_cvar_base(NODE *cref)
    01218 {
    01219     VALUE klass;
    01220
    01221     while (cref && cref->nd_next &&
    01222            (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) ||
    01223             (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) {
    01224         cref = cref->nd_next;
    01225
    01226         if (!cref->nd_next) {
    01227             rb_warn("class variable access from toplevel");
    01228         }
    01229     }
    01230
    01231     klass = cref->nd_clss;
    01232
    01233     if (NIL_P(klass)) {
    01234         rb_raise(rb_eTypeError, "no class variables available");
    01235     }
    01236     return klass;
    01237 }
    01238
    01239
    01240 #ifndef USE_IC_FOR_IVAR
    01241 #define USE_IC_FOR_IVAR 1
    01242 #endif
    01243
    01244 static VALUE
    01245 vm_getivar(VALUE obj, ID id, IC ic)
    01246 {
    01247 #if USE_IC_FOR_IVAR
    01248     if (TYPE(obj) ==  T_OBJECT) {
    01249         VALUE val = Qundef;
    01250         VALUE klass = RBASIC(obj)->klass;
    01251
    01252         if (ic->ic_class == klass) {
    01253             long index = ic->ic_value.index;
    01254             long len = ROBJECT_NUMIV(obj);
    01255             VALUE *ptr = ROBJECT_IVPTR(obj);
    01256
    01257             if (index < len) {
    01258                 val = ptr[index];
    01259             }
    01260         }
    01261         else {
    01262             st_data_t index;
    01263             long len = ROBJECT_NUMIV(obj);
    01264             VALUE *ptr = ROBJECT_IVPTR(obj);
    01265             struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
    01266
    01267             if (iv_index_tbl) {
    01268                 if (st_lookup(iv_index_tbl, id, &index)) {
    01269                     if ((long)index < len) {
    01270                         val = ptr[index];
    01271                     }
    01272                     ic->ic_class = klass;
    01273                     ic->ic_value.index = index;
    01274                 }
    01275             }
    01276         }
    01277         if (UNLIKELY(val == Qundef)) {
    01278             rb_warning("instance variable %s not initialized", rb_id2name(id));
    01279             val = Qnil;
    01280         }
    01281         return val;
    01282     }
    01283     else {
    01284         return rb_ivar_get(obj, id);
    01285     }
    01286 #else
    01287     return rb_ivar_get(obj, id);
    01288 #endif
    01289 }
    01290
    01291 static void
    01292 vm_setivar(VALUE obj, ID id, VALUE val, IC ic)
    01293 {
    01294 #if USE_IC_FOR_IVAR
    01295     if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) {
    01296         rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
    01297     }
    01298     if (OBJ_FROZEN(obj)) {
    01299         rb_error_frozen("object");
    01300     }
    01301
    01302     if (TYPE(obj) == T_OBJECT) {
    01303         VALUE klass = RBASIC(obj)->klass;
    01304         st_data_t index;
    01305
    01306         if (ic->ic_class == klass) {
    01307             long index = ic->ic_value.index;
    01308             long len = ROBJECT_NUMIV(obj);
    01309             VALUE *ptr = ROBJECT_IVPTR(obj);
    01310
    01311             if (index < len) {
    01312                 ptr[index] = val;
    01313                 return; /* inline cache hit */
    01314             }
    01315         }
    01316         else {
    01317             struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
    01318
    01319             if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
    01320                 ic->ic_class = klass;
    01321                 ic->ic_value.index = index;
    01322             }
    01323             /* fall through */
    01324         }
    01325     }
    01326     rb_ivar_set(obj, id, val);
    01327 #else
    01328     rb_ivar_set(obj, id, val);
    01329 #endif
    01330 }
    01331
    01332 static inline const rb_method_entry_t *
    01333 vm_method_search(VALUE id, VALUE klass, IC ic)
    01334 {
    01335     rb_method_entry_t *me;
    01336 #if OPT_INLINE_METHOD_CACHE
    01337     if (LIKELY(klass == ic->ic_class) &&
    01338         LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
    01339         me = ic->ic_value.method;
    01340     }
    01341     else {
    01342         me = rb_method_entry(klass, id);
    01343         ic->ic_class = klass;
    01344         ic->ic_value.method = me;
    01345         ic->ic_vmstat = GET_VM_STATE_VERSION();
    01346     }
    01347 #else
    01348     me = rb_method_entry(klass, id);
    01349 #endif
    01350     return me;
    01351 }
    01352
    01353 static inline VALUE
    01354 vm_search_normal_superclass(VALUE klass, VALUE recv)
    01355 {
    01356     if (BUILTIN_TYPE(klass) == T_CLASS) {
    01357         return RCLASS_SUPER(klass);
    01358     }
    01359     else if (BUILTIN_TYPE(klass) == T_MODULE) {
    01360         VALUE k = CLASS_OF(recv);
    01361         while (k) {
    01362             if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) {
    01363                 return RCLASS_SUPER(k);
    01364             }
    01365             k = RCLASS_SUPER(k);
    01366         }
    01367         return rb_cObject;
    01368     }
    01369     else {
    01370         rb_bug("vm_search_normal_superclass: should not be reach here");
    01371     }
    01372 }
    01373
    01374 static void
    01375 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip,
    01376                      VALUE recv, VALUE sigval,
    01377                      ID *idp, VALUE *klassp)
    01378 {
    01379     ID id;
    01380     VALUE klass;
    01381
    01382     while (ip && !ip->klass) {
    01383         ip = ip->parent_iseq;
    01384     }
    01385
    01386     if (ip == 0) {
    01387         rb_raise(rb_eNoMethodError, "super called outside of method");
    01388     }
    01389
    01390     id = ip->defined_method_id;
    01391
    01392     if (ip != ip->local_iseq) {
    01393         /* defined by Module#define_method() */
    01394         rb_control_frame_t *lcfp = GET_CFP();
    01395
    01396         if (!sigval) {
    01397             /* zsuper */
    01398             rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.");
    01399         }
    01400
    01401         while (lcfp->iseq != ip) {
    01402             VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
    01403             while (1) {
    01404                 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
    01405                 if (lcfp->dfp == tdfp) {
    01406                     break;
    01407                 }
    01408             }
    01409         }
    01410
    01411         /* temporary measure for [Bug #2420] [Bug #3136] */
    01412         if (!lcfp->me) {
    01413             rb_raise(rb_eNoMethodError, "super called outside of method");
    01414         }
    01415
    01416         id = lcfp->me->def->original_id;
    01417         klass = vm_search_normal_superclass(lcfp->me->klass, recv);
    01418     }
    01419     else {
    01420         klass = vm_search_normal_superclass(ip->klass, recv);
    01421     }
    01422
    01423     *idp = id;
    01424     *klassp = klass;
    01425 }
    01426
    01427 static VALUE
    01428 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
    01429          rb_num_t throw_state, VALUE throwobj)
    01430 {
    01431     int state = (int)(throw_state & 0xff);
    01432     int flag = (int)(throw_state & 0x8000);
    01433     rb_num_t level = throw_state >> 16;
    01434
    01435     if (state != 0) {
    01436         VALUE *pt = 0;
    01437         if (flag != 0) {
    01438             pt = (void *) 1;
    01439         }
    01440         else {
    01441             if (state == TAG_BREAK) {
    01442                 rb_control_frame_t *cfp = GET_CFP();
    01443                 VALUE *dfp = GET_DFP();
    01444                 int is_orphan = 1;
    01445                 rb_iseq_t *base_iseq = GET_ISEQ();
    01446
    01447               search_parent:
    01448                 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
    01449                     if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
    01450                         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
    01451                         dfp = cfp->dfp;
    01452                         goto search_parent;
    01453                     }
    01454                     dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
    01455                     base_iseq = base_iseq->parent_iseq;
    01456
    01457                     while ((VALUE *) cfp < th->stack + th->stack_size) {
    01458                         if (cfp->dfp == dfp) {
    01459                             goto search_parent;
    01460                         }
    01461                         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
    01462                     }
    01463                     rb_bug("VM (throw): can't find break base.");
    01464                 }
    01465
    01466                 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
    01467                     /* lambda{... break ...} */
    01468                     is_orphan = 0;
    01469                     pt = cfp->dfp;
    01470                     state = TAG_RETURN;
    01471                 }
    01472                 else {
    01473                     dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
    01474
    01475                     while ((VALUE *)cfp < th->stack + th->stack_size) {
    01476                         if (cfp->dfp == dfp) {
    01477                             VALUE epc = cfp->pc - cfp->iseq->iseq_encoded;
    01478                             rb_iseq_t *iseq = cfp->iseq;
    01479                             int i;
    01480
    01481                             for (i=0; i<iseq->catch_table_size; i++) {
    01482                                 struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
    01483
    01484                                 if (entry->type == CATCH_TYPE_BREAK &&
    01485                                     entry->start < epc && entry->end >= epc) {
    01486                                     if (entry->cont == epc) {
    01487                                         goto found;
    01488                                     }
    01489                                     else {
    01490                                         break;
    01491                                     }
    01492                                 }
    01493                             }
    01494                             break;
    01495
    01496                           found:
    01497                             pt = dfp;
    01498                             is_orphan = 0;
    01499                             break;
    01500                         }
    01501                         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
    01502                     }
    01503                 }
    01504
    01505                 if (is_orphan) {
    01506                     rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
    01507                 }
    01508             }
    01509             else if (state == TAG_RETRY) {
    01510                 rb_num_t i;
    01511                 pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
    01512                 for (i = 0; i < level; i++) {
    01513                     pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
    01514                 }
    01515             }
    01516             else if (state == TAG_RETURN) {
    01517                 rb_control_frame_t *cfp = GET_CFP();
    01518                 VALUE *dfp = GET_DFP();
    01519                 VALUE *lfp = GET_LFP();
    01520
    01521                 /* check orphan and get dfp */
    01522                 while ((VALUE *) cfp < th->stack + th->stack_size) {
    01523                     if (!lfp) {
    01524                         lfp = cfp->lfp;
    01525                     }
    01526                     if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) {
    01527                         lfp = 0;
    01528                     }
    01529
    01530                     if (cfp->lfp == lfp) {
    01531                         if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
    01532                             VALUE *tdfp = dfp;
    01533
    01534                             while (lfp != tdfp) {
    01535                                 if (cfp->dfp == tdfp) {
    01536                                     /* in lambda */
    01537                                     dfp = cfp->dfp;
    01538                                     goto valid_return;
    01539                                 }
    01540                                 tdfp = GC_GUARDED_PTR_REF((VALUE *)*tdfp);
    01541                             }
    01542                         }
    01543                     }
    01544
    01545                     if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_METHOD) {
    01546                         dfp = lfp;
    01547                         goto valid_return;
    01548                     }
    01549
    01550                     cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
    01551                 }
    01552
    01553                 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
    01554
    01555               valid_return:
    01556                 pt = dfp;
    01557             }
    01558             else {
    01559                 rb_bug("isns(throw): unsupport throw type");
    01560             }
    01561         }
    01562         th->state = state;
    01563         return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
    01564     }
    01565     else {
    01566         /* continue throw */
    01567         VALUE err = throwobj;
    01568
    01569         if (FIXNUM_P(err)) {
    01570             th->state = FIX2INT(err);
    01571         }
    01572         else if (SYMBOL_P(err)) {
    01573             th->state = TAG_THROW;
    01574         }
    01575         else if (BUILTIN_TYPE(err) == T_NODE) {
    01576             th->state = GET_THROWOBJ_STATE(err);
    01577         }
    01578         else {
    01579             th->state = TAG_RAISE;
    01580             /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
    01581         }
    01582         return err;
    01583     }
    01584 }
    01585
    01586 static inline void
    01587 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag)
    01588 {
    01589     int is_splat = flag & 0x01;
    01590     rb_num_t space_size = num + is_splat;
    01591     VALUE *base = cfp->sp, *ptr;
    01592     volatile VALUE tmp_ary;
    01593     rb_num_t len;
    01594
    01595     if (TYPE(ary) != T_ARRAY) {
    01596         ary = rb_ary_to_ary(ary);
    01597     }
    01598
    01599     cfp->sp += space_size;
    01600
    01601     tmp_ary = ary;
    01602     ptr = RARRAY_PTR(ary);
    01603     len = (rb_num_t)RARRAY_LEN(ary);
    01604
    01605     if (flag & 0x02) {
    01606         /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
    01607         rb_num_t i = 0, j;
    01608
    01609         if (len < num) {
    01610             for (i=0; i<num-len; i++) {
    01611                 *base++ = Qnil;
    01612             }
    01613         }
    01614         for (j=0; i<num; i++, j++) {
    01615             VALUE v = ptr[len - j - 1];
    01616             *base++ = v;
    01617         }
    01618         if (is_splat) {
    01619             *base = rb_ary_new4(len - j, ptr);
    01620         }
    01621     }
    01622     else {
    01623         /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
    01624         rb_num_t i;
    01625         VALUE *bptr = &base[space_size - 1];
    01626
    01627         for (i=0; i<num; i++) {
    01628             if (len <= i) {
    01629                 for (; i<num; i++) {
    01630                     *bptr-- = Qnil;
    01631                 }
    01632                 break;
    01633             }
    01634             *bptr-- = ptr[i];
    01635         }
    01636         if (is_splat) {
    01637             if (num > len) {
    01638                 *bptr = rb_ary_new();
    01639             }
    01640             else {
    01641                 *bptr = rb_ary_new4(len - num, ptr + num);
    01642             }
    01643         }
    01644     }
    01645 }
    01646
    01647 static inline int
    01648 check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
    01649 {
    01650     if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
    01651         me->def->body.cfunc.func == func) {
    01652         return 1;
    01653     }
    01654     else {
    01655         return 0;
    01656     }
    01657 }
    01658
    01659 static
    01660 #ifndef NO_BIG_INLINE
    01661 inline
    01662 #endif
    01663 VALUE
    01664 opt_eq_func(VALUE recv, VALUE obj, IC ic)
    01665 {
    01666     if (FIXNUM_2_P(recv, obj) &&
    01667         BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
    01668         return (recv == obj) ? Qtrue : Qfalse;
    01669     }
    01670     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
    01671         if (HEAP_CLASS_OF(recv) == rb_cFloat &&
    01672                  HEAP_CLASS_OF(obj) == rb_cFloat &&
    01673                  BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
    01674             double a = RFLOAT_VALUE(recv);
    01675             double b = RFLOAT_VALUE(obj);
    01676
    01677             if (isnan(a) || isnan(b)) {
    01678                 return Qfalse;
    01679             }
    01680             return  (a == b) ? Qtrue : Qfalse;
    01681         }
    01682         else if (HEAP_CLASS_OF(recv) == rb_cString &&
    01683                  HEAP_CLASS_OF(obj) == rb_cString &&
    01684                  BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
    01685             return rb_str_equal(recv, obj);
    01686         }
    01687     }
    01688
    01689     {
    01690         const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic);
    01691         extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
    01692
    01693         if (check_cfunc(me, rb_obj_equal)) {
    01694             return recv == obj ? Qtrue : Qfalse;
    01695         }
    01696     }
    01697
    01698     return Qundef;
    01699 }
    01700
    01701 struct opt_case_dispatch_i_arg {
    01702     VALUE obj;
    01703     int label;
    01704 };
    01705
    01706 static int
    01707 opt_case_dispatch_i(st_data_t key, st_data_t data, st_data_t p)
    01708 {
    01709     struct opt_case_dispatch_i_arg *arg = (void *)p;
    01710
    01711     if (RTEST(rb_funcall((VALUE)key, idEqq, 1, arg->obj))) {
    01712         arg->label = FIX2INT((VALUE)data);
    01713         return ST_STOP;
    01714     }
    01715     else {
    01716         return ST_CONTINUE;
    01717     }
    01718 }
    01719
    01720