vm.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   vm.c -
00004 
00005   $Author: nagachika $
00006 
00007   Copyright (C) 2004-2007 Koichi Sasada
00008 
00009 **********************************************************************/
00010 
00011 #include "ruby/ruby.h"
00012 #include "ruby/vm.h"
00013 #include "ruby/st.h"
00014 #include "ruby/encoding.h"
00015 #include "internal.h"
00016 
00017 #include "gc.h"
00018 #include "vm_core.h"
00019 #include "iseq.h"
00020 #include "eval_intern.h"
00021 #include "probes.h"
00022 #include "probes_helper.h"
00023 
00024 static inline VALUE *
00025 VM_EP_LEP(VALUE *ep)
00026 {
00027     while (!VM_EP_LEP_P(ep)) {
00028         ep = VM_EP_PREV_EP(ep);
00029     }
00030     return ep;
00031 }
00032 
00033 VALUE *
00034 rb_vm_ep_local_ep(VALUE *ep)
00035 {
00036     return VM_EP_LEP(ep);
00037 }
00038 
00039 static inline VALUE *
00040 VM_CF_LEP(rb_control_frame_t *cfp)
00041 {
00042     return VM_EP_LEP(cfp->ep);
00043 }
00044 
00045 static inline VALUE *
00046 VM_CF_PREV_EP(rb_control_frame_t * cfp)
00047 {
00048     return VM_EP_PREV_EP((cfp)->ep);
00049 }
00050 
00051 static inline rb_block_t *
00052 VM_CF_BLOCK_PTR(rb_control_frame_t *cfp)
00053 {
00054     VALUE *ep = VM_CF_LEP(cfp);
00055     return VM_EP_BLOCK_PTR(ep);
00056 }
00057 
00058 rb_block_t *
00059 rb_vm_control_frame_block_ptr(rb_control_frame_t *cfp)
00060 {
00061     return VM_CF_BLOCK_PTR(cfp);
00062 }
00063 
00064 #if VM_COLLECT_USAGE_DETAILS
00065 static void vm_collect_usage_operand(int insn, int n, VALUE op);
00066 static void vm_collect_usage_insn(int insn);
00067 static void vm_collect_usage_register(int reg, int isset);
00068 #endif
00069 
00070 static VALUE
00071 vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
00072                int argc, const VALUE *argv, const rb_block_t *blockptr);
00073 
00074 static rb_serial_t ruby_vm_global_method_state = 1;
00075 static rb_serial_t ruby_vm_global_constant_state = 1;
00076 static rb_serial_t ruby_vm_class_serial = 1;
00077 
00078 #include "vm_insnhelper.h"
00079 #include "vm_insnhelper.c"
00080 #include "vm_exec.h"
00081 #include "vm_exec.c"
00082 
00083 #include "vm_method.c"
00084 #include "vm_eval.c"
00085 
00086 #include <assert.h>
00087 
00088 #define BUFSIZE 0x100
00089 #define PROCDEBUG 0
00090 
00091 rb_serial_t
00092 rb_next_class_serial(void)
00093 {
00094     return NEXT_CLASS_SERIAL();
00095 }
00096 
00097 VALUE rb_cRubyVM;
00098 VALUE rb_cThread;
00099 VALUE rb_cEnv;
00100 VALUE rb_mRubyVMFrozenCore;
00101 
00102 VALUE ruby_vm_const_missing_count = 0;
00103 short ruby_vm_redefined_flag[BOP_LAST_];
00104 rb_thread_t *ruby_current_thread = 0;
00105 rb_vm_t *ruby_current_vm = 0;
00106 rb_event_flag_t ruby_vm_event_flags;
00107 
00108 static void thread_free(void *ptr);
00109 
00110 void
00111 rb_vm_inc_const_missing_count(void)
00112 {
00113     ruby_vm_const_missing_count +=1;
00114 }
00115 
00116 /*
00117  *  call-seq:
00118  *    RubyVM.stat -> Hash
00119  *    RubyVM.stat(hsh) -> hsh
00120  *    RubyVM.stat(Symbol) -> Numeric
00121  *
00122  *  Returns a Hash containing implementation-dependent counters inside the VM.
00123  *
00124  *  This hash includes information about method/constant cache serials:
00125  *
00126  *    {
00127  *      :global_method_state=>251,
00128  *      :global_constant_state=>481,
00129  *      :class_serial=>9029
00130  *    }
00131  *
00132  *  The contents of the hash are implementation specific and may be changed in
00133  *  the future.
00134  *
00135  *  This method is only expected to work on C Ruby.
00136  */
00137 
00138 static VALUE
00139 vm_stat(int argc, VALUE *argv, VALUE self)
00140 {
00141     static VALUE sym_global_method_state, sym_global_constant_state, sym_class_serial;
00142     VALUE arg = Qnil;
00143     VALUE hash = Qnil, key = Qnil;
00144 
00145     if (rb_scan_args(argc, argv, "01", &arg) == 1) {
00146         if (SYMBOL_P(arg))
00147             key = arg;
00148         else if (RB_TYPE_P(arg, T_HASH))
00149             hash = arg;
00150         else
00151             rb_raise(rb_eTypeError, "non-hash or symbol given");
00152     } else if (arg == Qnil) {
00153         hash = rb_hash_new();
00154     }
00155 
00156     if (sym_global_method_state == 0) {
00157 #define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
00158         S(global_method_state);
00159         S(global_constant_state);
00160         S(class_serial);
00161 #undef S
00162     }
00163 
00164 #define SET(name, attr) \
00165     if (key == sym_##name) \
00166         return SERIALT2NUM(attr); \
00167     else if (hash != Qnil) \
00168         rb_hash_aset(hash, sym_##name, SERIALT2NUM(attr));
00169 
00170     SET(global_method_state, ruby_vm_global_method_state);
00171     SET(global_constant_state, ruby_vm_global_constant_state);
00172     SET(class_serial, ruby_vm_class_serial);
00173 #undef SET
00174 
00175     if (key != Qnil) /* matched key should return above */
00176         rb_raise(rb_eArgError, "unknown key: %s", RSTRING_PTR(rb_id2str(SYM2ID(key))));
00177 
00178     return hash;
00179 }
00180 
00181 /* control stack frame */
00182 
00183 static void
00184 vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
00185 {
00186     rb_iseq_t *iseq;
00187     GetISeqPtr(iseqval, iseq);
00188 
00189     if (iseq->type != ISEQ_TYPE_TOP) {
00190         rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
00191     }
00192 
00193     /* for return */
00194     vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
00195                   th->top_self, rb_cObject, VM_ENVVAL_BLOCK_PTR(0),
00196                   iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
00197 }
00198 
00199 static void
00200 vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t *base_block)
00201 {
00202     rb_iseq_t *iseq;
00203     GetISeqPtr(iseqval, iseq);
00204 
00205     vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH,
00206                   base_block->self, base_block->klass,
00207                   VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded,
00208                   th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
00209 
00210     if (cref) {
00211         th->cfp->ep[-1] = (VALUE)cref;
00212     }
00213 }
00214 
00215 static void
00216 vm_set_main_stack(rb_thread_t *th, VALUE iseqval)
00217 {
00218     VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
00219     rb_binding_t *bind;
00220     rb_iseq_t *iseq;
00221     rb_env_t *env;
00222 
00223     GetBindingPtr(toplevel_binding, bind);
00224     GetEnvPtr(bind->env, env);
00225     vm_set_eval_stack(th, iseqval, 0, &env->block);
00226 
00227     /* save binding */
00228     GetISeqPtr(iseqval, iseq);
00229     if (bind && iseq->local_size > 0) {
00230         bind->env = rb_vm_make_env_object(th, th->cfp);
00231     }
00232 }
00233 
00234 rb_control_frame_t *
00235 rb_vm_get_binding_creatable_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp)
00236 {
00237     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00238         if (cfp->iseq) {
00239             return (rb_control_frame_t *)cfp;
00240         }
00241         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00242     }
00243     return 0;
00244 }
00245 
00246 rb_control_frame_t *
00247 rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp)
00248 {
00249     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00250         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00251             return (rb_control_frame_t *)cfp;
00252         }
00253         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00254     }
00255     return 0;
00256 }
00257 
00258 static rb_control_frame_t *
00259 vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
00260 {
00261     if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00262         return cfp;
00263     }
00264 
00265     cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00266 
00267     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00268         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00269             return cfp;
00270         }
00271 
00272         if ((cfp->flag & VM_FRAME_FLAG_PASSED) == 0) {
00273             break;
00274         }
00275         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00276     }
00277     return 0;
00278 }
00279 
00280 void
00281 rb_vm_pop_cfunc_frame(void)
00282 {
00283     rb_thread_t *th = GET_THREAD();
00284     const rb_method_entry_t *me = th->cfp->me;
00285     EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil);
00286     RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
00287     vm_pop_frame(th);
00288 }
00289 
00290 void
00291 rb_vm_rewind_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
00292 {
00293     /* check skipped frame */
00294     while (th->cfp != cfp) {
00295 #if VMDEBUG
00296         printf("skipped frame: %s\n", vm_frametype_name(th->cfp));
00297 #endif
00298         if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) {
00299             vm_pop_frame(th);
00300         }
00301         else { /* unlikely path */
00302             rb_vm_pop_cfunc_frame();
00303         }
00304     }
00305 }
00306 
00307 /* obsolete */
00308 void
00309 rb_frame_pop(void)
00310 {
00311     rb_thread_t *th = GET_THREAD();
00312     vm_pop_frame(th);
00313 }
00314 
00315 /* at exit */
00316 
00317 void
00318 ruby_vm_at_exit(void (*func)(rb_vm_t *))
00319 {
00320     rb_ary_push((VALUE)&GET_VM()->at_exit, (VALUE)func);
00321 }
00322 
00323 static void
00324 ruby_vm_run_at_exit_hooks(rb_vm_t *vm)
00325 {
00326     VALUE hook = (VALUE)&vm->at_exit;
00327 
00328     while (RARRAY_LEN(hook) > 0) {
00329         typedef void rb_vm_at_exit_func(rb_vm_t*);
00330         rb_vm_at_exit_func *func = (rb_vm_at_exit_func*)rb_ary_pop(hook);
00331         (*func)(vm);
00332     }
00333     rb_ary_free(hook);
00334 }
00335 
00336 /* Env */
00337 
00338 /*
00339   env{
00340     env[0] // special (block or prev env)
00341     env[1] // env object
00342   };
00343  */
00344 
00345 #define ENV_IN_HEAP_P(th, env)  \
00346   (!((th)->stack <= (env) && (env) < ((th)->stack + (th)->stack_size)))
00347 #define ENV_VAL(env)        ((env)[1])
00348 
00349 static void
00350 env_mark(void * const ptr)
00351 {
00352     RUBY_MARK_ENTER("env");
00353     if (ptr) {
00354         const rb_env_t * const env = ptr;
00355 
00356         if (env->env) {
00357             /* TODO: should mark more restricted range */
00358             RUBY_GC_INFO("env->env\n");
00359             rb_gc_mark_locations(env->env, env->env + env->env_size);
00360         }
00361 
00362         RUBY_GC_INFO("env->prev_envval\n");
00363         RUBY_MARK_UNLESS_NULL(env->prev_envval);
00364         RUBY_MARK_UNLESS_NULL(env->block.self);
00365         RUBY_MARK_UNLESS_NULL(env->block.proc);
00366 
00367         if (env->block.iseq) {
00368             if (BUILTIN_TYPE(env->block.iseq) == T_NODE) {
00369                 RUBY_MARK_UNLESS_NULL((VALUE)env->block.iseq);
00370             }
00371             else {
00372                 RUBY_MARK_UNLESS_NULL(env->block.iseq->self);
00373             }
00374         }
00375     }
00376     RUBY_MARK_LEAVE("env");
00377 }
00378 
00379 static void
00380 env_free(void * const ptr)
00381 {
00382     RUBY_FREE_ENTER("env");
00383     if (ptr) {
00384         rb_env_t *const env = ptr;
00385         RUBY_FREE_UNLESS_NULL(env->env);
00386         ruby_xfree(ptr);
00387     }
00388     RUBY_FREE_LEAVE("env");
00389 }
00390 
00391 static size_t
00392 env_memsize(const void *ptr)
00393 {
00394     if (ptr) {
00395         const rb_env_t * const env = ptr;
00396         size_t size = sizeof(rb_env_t);
00397         if (env->env) {
00398             size += env->env_size * sizeof(VALUE);
00399         }
00400         return size;
00401     }
00402     return 0;
00403 }
00404 
00405 static const rb_data_type_t env_data_type = {
00406     "VM/env",
00407     {env_mark, env_free, env_memsize,},
00408     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00409 };
00410 
00411 static VALUE
00412 env_alloc(void)
00413 {
00414     VALUE obj;
00415     rb_env_t *env;
00416     obj = TypedData_Make_Struct(rb_cEnv, rb_env_t, &env_data_type, env);
00417     env->env = 0;
00418     env->prev_envval = 0;
00419     env->block.iseq = 0;
00420     return obj;
00421 }
00422 
00423 static VALUE check_env_value(VALUE envval);
00424 
00425 static int
00426 check_env(rb_env_t * const env)
00427 {
00428     fprintf(stderr, "---\n");
00429     fprintf(stderr, "envptr: %p\n", (void *)&env->block.ep[0]);
00430     fprintf(stderr, "envval: %10p ", (void *)env->block.ep[1]);
00431     dp(env->block.ep[1]);
00432     fprintf(stderr, "ep:    %10p\n", (void *)env->block.ep);
00433     if (env->prev_envval) {
00434         fprintf(stderr, ">>\n");
00435         check_env_value(env->prev_envval);
00436         fprintf(stderr, "<<\n");
00437     }
00438     return 1;
00439 }
00440 
00441 static VALUE
00442 check_env_value(VALUE envval)
00443 {
00444     rb_env_t *env;
00445     GetEnvPtr(envval, env);
00446 
00447     if (check_env(env)) {
00448         return envval;
00449     }
00450     rb_bug("invalid env");
00451     return Qnil;                /* unreachable */
00452 }
00453 
00454 static VALUE
00455 vm_make_env_each(rb_thread_t * const th, rb_control_frame_t * const cfp,
00456                  VALUE *envptr, VALUE * const endptr)
00457 {
00458     VALUE envval, penvval = 0;
00459     rb_env_t *env;
00460     VALUE *nenvptr;
00461     int i, local_size;
00462 
00463     if (ENV_IN_HEAP_P(th, envptr)) {
00464         return ENV_VAL(envptr);
00465     }
00466 
00467     if (envptr != endptr) {
00468         VALUE *penvptr = GC_GUARDED_PTR_REF(*envptr);
00469         rb_control_frame_t *pcfp = cfp;
00470 
00471         if (ENV_IN_HEAP_P(th, penvptr)) {
00472             penvval = ENV_VAL(penvptr);
00473         }
00474         else {
00475             while (pcfp->ep != penvptr) {
00476                 pcfp++;
00477                 if (pcfp->ep == 0) {
00478                     SDR();
00479                     rb_bug("invalid ep");
00480                 }
00481             }
00482             penvval = vm_make_env_each(th, pcfp, penvptr, endptr);
00483             *envptr = VM_ENVVAL_PREV_EP_PTR(pcfp->ep);
00484         }
00485     }
00486 
00487     /* allocate env */
00488     envval = env_alloc();
00489     GetEnvPtr(envval, env);
00490 
00491     if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00492         local_size = 2;
00493     }
00494     else {
00495         local_size = cfp->iseq->local_size;
00496     }
00497 
00498     env->env_size = local_size + 1 + 1;
00499     env->local_size = local_size;
00500     env->env = ALLOC_N(VALUE, env->env_size);
00501     env->prev_envval = penvval;
00502 
00503     for (i = 0; i <= local_size; i++) {
00504         env->env[i] = envptr[-local_size + i];
00505 #if 0
00506         fprintf(stderr, "%2d ", &envptr[-local_size + i] - th->stack); dp(env->env[i]);
00507         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00508             /* clear value stack for GC */
00509             envptr[-local_size + i] = 0;
00510         }
00511 #endif
00512     }
00513 
00514     *envptr = envval;           /* GC mark */
00515     nenvptr = &env->env[i - 1];
00516     nenvptr[1] = envval;        /* frame self */
00517 
00518     /* reset ep in cfp */
00519     cfp->ep = nenvptr;
00520 
00521     /* as Binding */
00522     env->block.self = cfp->self;
00523     env->block.ep = cfp->ep;
00524     env->block.iseq = cfp->iseq;
00525 
00526     if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00527         /* TODO */
00528         env->block.iseq = 0;
00529     }
00530     return envval;
00531 }
00532 
00533 static int
00534 collect_local_variables_in_iseq(rb_iseq_t *iseq, const VALUE ary)
00535 {
00536     int i;
00537     if (!iseq) return 0;
00538     for (i = 0; i < iseq->local_table_size; i++) {
00539         ID lid = iseq->local_table[i];
00540         if (rb_is_local_id(lid)) {
00541             rb_ary_push(ary, ID2SYM(lid));
00542         }
00543     }
00544     return 1;
00545 }
00546 
00547 static int
00548 collect_local_variables_in_env(rb_env_t * env, const VALUE ary)
00549 {
00550 
00551     while (collect_local_variables_in_iseq(env->block.iseq, ary),
00552            env->prev_envval) {
00553         GetEnvPtr(env->prev_envval, env);
00554     }
00555     return 0;
00556 }
00557 
00558 static int
00559 vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *ep, VALUE ary)
00560 {
00561     if (ENV_IN_HEAP_P(th, ep)) {
00562         rb_env_t *env;
00563         GetEnvPtr(ENV_VAL(ep), env);
00564         collect_local_variables_in_env(env, ary);
00565         return 1;
00566     }
00567     else {
00568         return 0;
00569     }
00570 }
00571 
00572 static void vm_rewrite_ep_in_errinfo(rb_thread_t *th);
00573 static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block);
00574 static VALUE vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp, VALUE *blockprocptr);
00575 
00576 VALUE
00577 rb_vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp)
00578 {
00579     VALUE blockprocval;
00580     return vm_make_env_object(th, cfp, &blockprocval);
00581 }
00582 
00583 static VALUE
00584 vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp, VALUE *blockprocptr)
00585 {
00586     VALUE envval;
00587     VALUE *lep = VM_CF_LEP(cfp);
00588     rb_block_t *blockptr = VM_EP_BLOCK_PTR(lep);
00589 
00590     if (blockptr) {
00591         VALUE blockprocval = vm_make_proc_from_block(th, blockptr);
00592         rb_proc_t *p;
00593         GetProcPtr(blockprocval, p);
00594         lep[0] = VM_ENVVAL_BLOCK_PTR(&p->block);
00595         *blockprocptr = blockprocval;
00596     }
00597 
00598     envval = vm_make_env_each(th, cfp, cfp->ep, lep);
00599     vm_rewrite_ep_in_errinfo(th);
00600 
00601     if (PROCDEBUG) {
00602         check_env_value(envval);
00603     }
00604 
00605     return envval;
00606 }
00607 
00608 static void
00609 vm_rewrite_ep_in_errinfo(rb_thread_t *th)
00610 {
00611     rb_control_frame_t *cfp = th->cfp;
00612     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00613         /* rewrite ep in errinfo to point to heap */
00614         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
00615             (cfp->iseq->type == ISEQ_TYPE_RESCUE ||
00616              cfp->iseq->type == ISEQ_TYPE_ENSURE)) {
00617             VALUE errinfo = cfp->ep[-2]; /* #$! */
00618             if (RB_TYPE_P(errinfo, T_NODE)) {
00619                 VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(errinfo);
00620                 if (! ENV_IN_HEAP_P(th, escape_ep)) {
00621                     VALUE epval = *escape_ep;
00622                     if (!SPECIAL_CONST_P(epval) && RBASIC(epval)->klass == rb_cEnv) {
00623                         rb_env_t *epenv;
00624                         GetEnvPtr(epval, epenv);
00625                         SET_THROWOBJ_CATCH_POINT(errinfo, (VALUE)(epenv->env + epenv->local_size));
00626                     }
00627                 }
00628             }
00629         }
00630         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00631     }
00632 }
00633 
00634 void
00635 rb_vm_stack_to_heap(rb_thread_t *th)
00636 {
00637     rb_control_frame_t *cfp = th->cfp;
00638     while ((cfp = rb_vm_get_binding_creatable_next_cfp(th, cfp)) != 0) {
00639         rb_vm_make_env_object(th, cfp);
00640         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00641     }
00642 }
00643 
00644 /* Proc */
00645 
00646 static VALUE
00647 vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block)
00648 {
00649     if (!block->proc) {
00650         block->proc = rb_vm_make_proc(th, block, rb_cProc);
00651     }
00652     return block->proc;
00653 }
00654 
00655 VALUE
00656 rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
00657 {
00658     VALUE procval, envval, blockprocval = 0;
00659     rb_proc_t *proc;
00660     rb_control_frame_t *cfp = RUBY_VM_GET_CFP_FROM_BLOCK_PTR(block);
00661 
00662     if (block->proc) {
00663         rb_bug("rb_vm_make_proc: Proc value is already created.");
00664     }
00665 
00666     envval = vm_make_env_object(th, cfp, &blockprocval);
00667 
00668     if (PROCDEBUG) {
00669         check_env_value(envval);
00670     }
00671     procval = rb_proc_alloc(klass);
00672     GetProcPtr(procval, proc);
00673     proc->blockprocval = blockprocval;
00674     proc->block.self = block->self;
00675     proc->block.klass = block->klass;
00676     proc->block.ep = block->ep;
00677     proc->block.iseq = block->iseq;
00678     proc->block.proc = procval;
00679     proc->envval = envval;
00680     proc->safe_level = th->safe_level;
00681 
00682     if (VMDEBUG) {
00683         if (th->stack < block->ep && block->ep < th->stack + th->stack_size) {
00684             rb_bug("invalid ptr: block->ep");
00685         }
00686     }
00687 
00688     return procval;
00689 }
00690 
00691 /* Binding */
00692 
00693 VALUE
00694 rb_vm_make_binding(rb_thread_t *th, const rb_control_frame_t *src_cfp)
00695 {
00696     rb_control_frame_t *cfp = rb_vm_get_binding_creatable_next_cfp(th, src_cfp);
00697     rb_control_frame_t *ruby_level_cfp = rb_vm_get_ruby_level_next_cfp(th, src_cfp);
00698     VALUE bindval, envval;
00699     rb_binding_t *bind;
00700     VALUE blockprocval = 0;
00701 
00702     if (cfp == 0 || ruby_level_cfp == 0) {
00703         rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
00704     }
00705 
00706     while (1) {
00707         envval = vm_make_env_object(th, cfp, &blockprocval);
00708         if (cfp == ruby_level_cfp) {
00709             break;
00710         }
00711         cfp = rb_vm_get_binding_creatable_next_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
00712     }
00713 
00714     bindval = rb_binding_alloc(rb_cBinding);
00715     GetBindingPtr(bindval, bind);
00716     bind->env = envval;
00717     bind->path = ruby_level_cfp->iseq->location.path;
00718     bind->blockprocval = blockprocval;
00719     bind->first_lineno = rb_vm_get_sourceline(ruby_level_cfp);
00720 
00721     return bindval;
00722 }
00723 
00724 VALUE *
00725 rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynvars)
00726 {
00727     VALUE envval = bind->env, path = bind->path, iseqval;
00728     rb_env_t *env;
00729     rb_block_t *base_block;
00730     rb_thread_t *th = GET_THREAD();
00731     rb_iseq_t *base_iseq;
00732     NODE *node = 0;
00733     ID minibuf[4], *dyns = minibuf;
00734     VALUE idtmp = 0;
00735     VALUE blockprocval = 0;
00736 
00737     if (dyncount < 0) return 0;
00738 
00739     GetEnvPtr(envval, env);
00740 
00741     base_block = &env->block;
00742     base_iseq = base_block->iseq;
00743 
00744     if (dyncount >= numberof(minibuf)) dyns = ALLOCV_N(ID, idtmp, dyncount + 1);
00745 
00746     dyns[0] = dyncount;
00747     MEMCPY(dyns + 1, dynvars, ID, dyncount);
00748     node = NEW_NODE(NODE_SCOPE, dyns, 0, 0);
00749 
00750     iseqval = rb_iseq_new(node, base_iseq->location.label, path, path,
00751                           base_iseq->self, ISEQ_TYPE_EVAL);
00752     node->u1.tbl = 0; /* reset table */
00753     ALLOCV_END(idtmp);
00754 
00755     vm_set_eval_stack(th, iseqval, 0, base_block);
00756     bind->env = vm_make_env_object(th, th->cfp, &blockprocval);
00757     bind->blockprocval = blockprocval;
00758     vm_pop_frame(th);
00759     GetEnvPtr(bind->env, env);
00760 
00761     return env->env;
00762 }
00763 
00764 /* C -> Ruby: block */
00765 
00766 static inline VALUE
00767 invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
00768                     VALUE self, int argc, const VALUE *argv,
00769                     const rb_block_t *blockptr, const NODE *cref,
00770                     VALUE defined_class)
00771 {
00772     if (SPECIAL_CONST_P(block->iseq)) {
00773         return Qnil;
00774     }
00775     else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
00776         VALUE ret;
00777         const rb_iseq_t *iseq = block->iseq;
00778         const rb_control_frame_t *cfp;
00779         int i, opt_pc, arg_size = iseq->arg_size;
00780         int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
00781         const rb_method_entry_t *me = th->passed_bmethod_me;
00782         th->passed_bmethod_me = 0;
00783         cfp = th->cfp;
00784 
00785         for (i=0; i<argc; i++) {
00786             cfp->sp[i] = argv[i];
00787         }
00788 
00789         opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
00790                                      type == VM_FRAME_MAGIC_LAMBDA);
00791 
00792         if (me != 0) {
00793             /* bmethod */
00794             vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD,
00795                           self, defined_class,
00796                           VM_ENVVAL_PREV_EP_PTR(block->ep),
00797                           iseq->iseq_encoded + opt_pc,
00798                           cfp->sp + arg_size, iseq->local_size - arg_size,
00799                           me, iseq->stack_max);
00800 
00801             RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->klass, me->called_id);
00802             EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->klass, Qnil);
00803         }
00804         else {
00805             vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
00806                           self, defined_class,
00807                           VM_ENVVAL_PREV_EP_PTR(block->ep),
00808                           iseq->iseq_encoded + opt_pc,
00809                           cfp->sp + arg_size, iseq->local_size - arg_size,
00810                           0, iseq->stack_max);
00811         }
00812 
00813         if (cref) {
00814             th->cfp->ep[-1] = (VALUE)cref;
00815         }
00816 
00817         ret = vm_exec(th);
00818 
00819         if (me) {
00820             /* bmethod */
00821             EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->klass, ret);
00822             RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
00823         }
00824 
00825         return ret;
00826     }
00827     else {
00828         return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
00829     }
00830 }
00831 
00832 static inline const rb_block_t *
00833 check_block(rb_thread_t *th)
00834 {
00835     const rb_block_t *blockptr = VM_CF_BLOCK_PTR(th->cfp);
00836 
00837     if (blockptr == 0) {
00838         rb_vm_localjump_error("no block given", Qnil, 0);
00839     }
00840 
00841     return blockptr;
00842 }
00843 
00844 static inline VALUE
00845 vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref)
00846 {
00847     const rb_block_t *blockptr = check_block(th);
00848     return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref,
00849                                blockptr->klass);
00850 }
00851 
00852 static inline VALUE
00853 vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
00854 {
00855     const rb_block_t *blockptr = check_block(th);
00856     return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0,
00857                                blockptr->klass);
00858 }
00859 
00860 static inline VALUE
00861 vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, const rb_block_t *blockargptr)
00862 {
00863     const rb_block_t *blockptr = check_block(th);
00864     return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0,
00865                                blockptr->klass);
00866 }
00867 
00868 static VALUE
00869 vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
00870                int argc, const VALUE *argv, const rb_block_t *blockptr)
00871 {
00872     VALUE val = Qundef;
00873     int state;
00874     volatile int stored_safe = th->safe_level;
00875 
00876     TH_PUSH_TAG(th);
00877     if ((state = EXEC_TAG()) == 0) {
00878         if (!proc->is_from_method) {
00879             th->safe_level = proc->safe_level;
00880         }
00881         val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0,
00882                                   defined_class);
00883     }
00884     TH_POP_TAG();
00885 
00886     if (!proc->is_from_method) {
00887         th->safe_level = stored_safe;
00888     }
00889 
00890     if (state) {
00891         JUMP_TAG(state);
00892     }
00893     return val;
00894 }
00895 
00896 VALUE
00897 rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
00898                   int argc, const VALUE *argv, const rb_block_t *blockptr)
00899 {
00900     return vm_invoke_proc(th, proc, proc->block.self, proc->block.klass,
00901                           argc, argv, blockptr);
00902 }
00903 
00904 /* special variable */
00905 
00906 static rb_control_frame_t *
00907 vm_normal_frame(rb_thread_t *th, rb_control_frame_t *cfp)
00908 {
00909     while (cfp->pc == 0) {
00910         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00911         if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00912             return 0;
00913         }
00914     }
00915     return cfp;
00916 }
00917 
00918 static VALUE
00919 vm_cfp_svar_get(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key)
00920 {
00921     cfp = vm_normal_frame(th, cfp);
00922     return lep_svar_get(th, cfp ? VM_CF_LEP(cfp) : 0, key);
00923 }
00924 
00925 static void
00926 vm_cfp_svar_set(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key, const VALUE val)
00927 {
00928     cfp = vm_normal_frame(th, cfp);
00929     lep_svar_set(th, cfp ? VM_CF_LEP(cfp) : 0, key, val);
00930 }
00931 
00932 static VALUE
00933 vm_svar_get(VALUE key)
00934 {
00935     rb_thread_t *th = GET_THREAD();
00936     return vm_cfp_svar_get(th, th->cfp, key);
00937 }
00938 
00939 static void
00940 vm_svar_set(VALUE key, VALUE val)
00941 {
00942     rb_thread_t *th = GET_THREAD();
00943     vm_cfp_svar_set(th, th->cfp, key, val);
00944 }
00945 
00946 VALUE
00947 rb_backref_get(void)
00948 {
00949     return vm_svar_get(1);
00950 }
00951 
00952 void
00953 rb_backref_set(VALUE val)
00954 {
00955     vm_svar_set(1, val);
00956 }
00957 
00958 VALUE
00959 rb_lastline_get(void)
00960 {
00961     return vm_svar_get(0);
00962 }
00963 
00964 void
00965 rb_lastline_set(VALUE val)
00966 {
00967     vm_svar_set(0, val);
00968 }
00969 
00970 /* misc */
00971 
00972 VALUE
00973 rb_sourcefilename(void)
00974 {
00975     rb_thread_t *th = GET_THREAD();
00976     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00977 
00978     if (cfp) {
00979         return cfp->iseq->location.path;
00980     }
00981     else {
00982         return Qnil;
00983     }
00984 }
00985 
00986 const char *
00987 rb_sourcefile(void)
00988 {
00989     rb_thread_t *th = GET_THREAD();
00990     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00991 
00992     if (cfp) {
00993         return RSTRING_PTR(cfp->iseq->location.path);
00994     }
00995     else {
00996         return 0;
00997     }
00998 }
00999 
01000 int
01001 rb_sourceline(void)
01002 {
01003     rb_thread_t *th = GET_THREAD();
01004     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
01005 
01006     if (cfp) {
01007         return rb_vm_get_sourceline(cfp);
01008     }
01009     else {
01010         return 0;
01011     }
01012 }
01013 
01014 NODE *
01015 rb_vm_cref(void)
01016 {
01017     rb_thread_t *th = GET_THREAD();
01018     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
01019 
01020     if (cfp == 0) {
01021         return NULL;
01022     }
01023     return rb_vm_get_cref(cfp->iseq, cfp->ep);
01024 }
01025 
01026 NODE *
01027 rb_vm_cref_in_context(VALUE self)
01028 {
01029     rb_thread_t *th = GET_THREAD();
01030     const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
01031     if (cfp->self != self) return NULL;
01032     return rb_vm_get_cref(cfp->iseq, cfp->ep);
01033 }
01034 
01035 #if 0
01036 void
01037 debug_cref(NODE *cref)
01038 {
01039     while (cref) {
01040         dp(cref->nd_clss);
01041         printf("%ld\n", cref->nd_visi);
01042         cref = cref->nd_next;
01043     }
01044 }
01045 #endif
01046 
01047 VALUE
01048 rb_vm_cbase(void)
01049 {
01050     rb_thread_t *th = GET_THREAD();
01051     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
01052 
01053     if (cfp == 0) {
01054         rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread");
01055     }
01056     return vm_get_cbase(cfp->iseq, cfp->ep);
01057 }
01058 
01059 /* jump */
01060 
01061 static VALUE
01062 make_localjump_error(const char *mesg, VALUE value, int reason)
01063 {
01064     extern VALUE rb_eLocalJumpError;
01065     VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
01066     ID id;
01067 
01068     switch (reason) {
01069       case TAG_BREAK:
01070         CONST_ID(id, "break");
01071         break;
01072       case TAG_REDO:
01073         CONST_ID(id, "redo");
01074         break;
01075       case TAG_RETRY:
01076         CONST_ID(id, "retry");
01077         break;
01078       case TAG_NEXT:
01079         CONST_ID(id, "next");
01080         break;
01081       case TAG_RETURN:
01082         CONST_ID(id, "return");
01083         break;
01084       default:
01085         CONST_ID(id, "noreason");
01086         break;
01087     }
01088     rb_iv_set(exc, "@exit_value", value);
01089     rb_iv_set(exc, "@reason", ID2SYM(id));
01090     return exc;
01091 }
01092 
01093 void
01094 rb_vm_localjump_error(const char *mesg, VALUE value, int reason)
01095 {
01096     VALUE exc = make_localjump_error(mesg, value, reason);
01097     rb_exc_raise(exc);
01098 }
01099 
01100 VALUE
01101 rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
01102 {
01103     VALUE result = Qnil;
01104 
01105     if (val == Qundef) {
01106         val = GET_THREAD()->tag->retval;
01107     }
01108     switch (state) {
01109       case 0:
01110         break;
01111       case TAG_RETURN:
01112         result = make_localjump_error("unexpected return", val, state);
01113         break;
01114       case TAG_BREAK:
01115         result = make_localjump_error("unexpected break", val, state);
01116         break;
01117       case TAG_NEXT:
01118         result = make_localjump_error("unexpected next", val, state);
01119         break;
01120       case TAG_REDO:
01121         result = make_localjump_error("unexpected redo", Qnil, state);
01122         break;
01123       case TAG_RETRY:
01124         result = make_localjump_error("retry outside of rescue clause", Qnil, state);
01125         break;
01126       default:
01127         break;
01128     }
01129     return result;
01130 }
01131 
01132 void
01133 rb_vm_jump_tag_but_local_jump(int state)
01134 {
01135     VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
01136     if (!NIL_P(exc)) rb_exc_raise(exc);
01137     JUMP_TAG(state);
01138 }
01139 
01140 NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val));
01141 
01142 static void
01143 vm_iter_break(rb_thread_t *th, VALUE val)
01144 {
01145     rb_control_frame_t *cfp = th->cfp;
01146     VALUE *ep = VM_CF_PREV_EP(cfp);
01147 
01148     th->state = TAG_BREAK;
01149     th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)ep, TAG_BREAK);
01150     TH_JUMP_TAG(th, TAG_BREAK);
01151 }
01152 
01153 void
01154 rb_iter_break(void)
01155 {
01156     vm_iter_break(GET_THREAD(), Qnil);
01157 }
01158 
01159 void
01160 rb_iter_break_value(VALUE val)
01161 {
01162     vm_iter_break(GET_THREAD(), val);
01163 }
01164 
01165 /* optimization: redefine management */
01166 
01167 static st_table *vm_opt_method_table = 0;
01168 
01169 static int
01170 vm_redefinition_check_flag(VALUE klass)
01171 {
01172     if (klass == rb_cFixnum) return FIXNUM_REDEFINED_OP_FLAG;
01173     if (klass == rb_cFloat)  return FLOAT_REDEFINED_OP_FLAG;
01174     if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG;
01175     if (klass == rb_cArray)  return ARRAY_REDEFINED_OP_FLAG;
01176     if (klass == rb_cHash)   return HASH_REDEFINED_OP_FLAG;
01177     if (klass == rb_cBignum) return BIGNUM_REDEFINED_OP_FLAG;
01178     if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG;
01179     if (klass == rb_cTime)   return TIME_REDEFINED_OP_FLAG;
01180     if (klass == rb_cRegexp) return REGEXP_REDEFINED_OP_FLAG;
01181     return 0;
01182 }
01183 
01184 static void
01185 rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
01186 {
01187     st_data_t bop;
01188     if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) {
01189         if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
01190             int flag = vm_redefinition_check_flag(klass);
01191 
01192             ruby_vm_redefined_flag[bop] |= flag;
01193         }
01194     }
01195 }
01196 
01197 static int
01198 check_redefined_method(st_data_t key, st_data_t value, st_data_t data)
01199 {
01200     ID mid = (ID)key;
01201     rb_method_entry_t *me = (rb_method_entry_t *)value;
01202     VALUE klass = (VALUE)data;
01203     rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL);
01204 
01205     if (newme != me)
01206         rb_vm_check_redefinition_opt_method(me, me->klass);
01207     return ST_CONTINUE;
01208 }
01209 
01210 void
01211 rb_vm_check_redefinition_by_prepend(VALUE klass)
01212 {
01213     if (!vm_redefinition_check_flag(klass)) return;
01214     st_foreach(RCLASS_M_TBL(RCLASS_ORIGIN(klass)), check_redefined_method,
01215                (st_data_t)klass);
01216 }
01217 
01218 static void
01219 add_opt_method(VALUE klass, ID mid, VALUE bop)
01220 {
01221     rb_method_entry_t *me;
01222     if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) && me->def &&
01223         me->def->type == VM_METHOD_TYPE_CFUNC) {
01224         st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
01225     }
01226     else {
01227         rb_bug("undefined optimized method: %s", rb_id2name(mid));
01228     }
01229 }
01230 
01231 static void
01232 vm_init_redefined_flag(void)
01233 {
01234     ID mid;
01235     VALUE bop;
01236 
01237     vm_opt_method_table = st_init_numtable();
01238 
01239 #define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)
01240 #define C(k) add_opt_method(rb_c##k, mid, bop)
01241     OP(PLUS, PLUS), (C(Fixnum), C(Float), C(String), C(Array));
01242     OP(MINUS, MINUS), (C(Fixnum), C(Float));
01243     OP(MULT, MULT), (C(Fixnum), C(Float));
01244     OP(DIV, DIV), (C(Fixnum), C(Float));
01245     OP(MOD, MOD), (C(Fixnum), C(Float));
01246     OP(Eq, EQ), (C(Fixnum), C(Float), C(String));
01247     OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String));
01248     OP(LT, LT), (C(Fixnum), C(Float));
01249     OP(LE, LE), (C(Fixnum), C(Float));
01250     OP(GT, GT), (C(Fixnum), C(Float));
01251     OP(GE, GE), (C(Fixnum), C(Float));
01252     OP(LTLT, LTLT), (C(String), C(Array));
01253     OP(AREF, AREF), (C(Array), C(Hash));
01254     OP(ASET, ASET), (C(Array), C(Hash));
01255     OP(Length, LENGTH), (C(Array), C(String), C(Hash));
01256     OP(Size, SIZE), (C(Array), C(String), C(Hash));
01257     OP(EmptyP, EMPTY_P), (C(Array), C(String), C(Hash));
01258     OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
01259     OP(EqTilde, MATCH), (C(Regexp), C(String));
01260     OP(Freeze, FREEZE), (C(String));
01261 #undef C
01262 #undef OP
01263 }
01264 
01265 /* for vm development */
01266 
01267 #if VMDEBUG
01268 static const char *
01269 vm_frametype_name(const rb_control_frame_t *cfp)
01270 {
01271     switch (VM_FRAME_TYPE(cfp)) {
01272       case VM_FRAME_MAGIC_METHOD: return "method";
01273       case VM_FRAME_MAGIC_BLOCK:  return "block";
01274       case VM_FRAME_MAGIC_CLASS:  return "class";
01275       case VM_FRAME_MAGIC_TOP:    return "top";
01276       case VM_FRAME_MAGIC_CFUNC:  return "cfunc";
01277       case VM_FRAME_MAGIC_PROC:   return "proc";
01278       case VM_FRAME_MAGIC_IFUNC:  return "ifunc";
01279       case VM_FRAME_MAGIC_EVAL:   return "eval";
01280       case VM_FRAME_MAGIC_LAMBDA: return "lambda";
01281       case VM_FRAME_MAGIC_RESCUE: return "rescue";
01282       default:
01283         rb_bug("unknown frame");
01284     }
01285 }
01286 #endif
01287 
01288 /* evaluator body */
01289 
01290 /*                  finish
01291   VMe (h1)          finish
01292     VM              finish F1 F2
01293       cfunc         finish F1 F2 C1
01294         rb_funcall  finish F1 F2 C1
01295           VMe       finish F1 F2 C1
01296             VM      finish F1 F2 C1 F3
01297 
01298   F1 - F3 : pushed by VM
01299   C1      : pushed by send insn (CFUNC)
01300 
01301   struct CONTROL_FRAME {
01302     VALUE *pc;                  // cfp[0], program counter
01303     VALUE *sp;                  // cfp[1], stack pointer
01304     VALUE *bp;                  // cfp[2], base pointer
01305     rb_iseq_t *iseq;            // cfp[3], iseq
01306     VALUE flag;                 // cfp[4], magic
01307     VALUE self;                 // cfp[5], self
01308     VALUE *ep;                  // cfp[6], env pointer
01309     rb_iseq_t * block_iseq;     // cfp[7], block iseq
01310     VALUE proc;                 // cfp[8], always 0
01311   };
01312 
01313   struct BLOCK {
01314     VALUE self;
01315     VALUE *ep;
01316     rb_iseq_t *block_iseq;
01317     VALUE proc;
01318   };
01319 
01320   struct METHOD_CONTROL_FRAME {
01321     rb_control_frame_t frame;
01322   };
01323 
01324   struct METHOD_FRAME {
01325     VALUE arg0;
01326     ...
01327     VALUE argM;
01328     VALUE param0;
01329     ...
01330     VALUE paramN;
01331     VALUE cref;
01332     VALUE special;                         // lep [1]
01333     struct block_object *block_ptr | 0x01; // lep [0]
01334   };
01335 
01336   struct BLOCK_CONTROL_FRAME {
01337     rb_control_frame_t frame;
01338   };
01339 
01340   struct BLOCK_FRAME {
01341     VALUE arg0;
01342     ...
01343     VALUE argM;
01344     VALUE param0;
01345     ...
01346     VALUE paramN;
01347     VALUE cref;
01348     VALUE *(prev_ptr | 0x01); // ep[0]
01349   };
01350 
01351   struct CLASS_CONTROL_FRAME {
01352     rb_control_frame_t frame;
01353   };
01354 
01355   struct CLASS_FRAME {
01356     VALUE param0;
01357     ...
01358     VALUE paramN;
01359     VALUE cref;
01360     VALUE prev_ep; // for frame jump
01361   };
01362 
01363   struct C_METHOD_CONTROL_FRAME {
01364     VALUE *pc;                       // 0
01365     VALUE *sp;                       // stack pointer
01366     VALUE *bp;                       // base pointer (used in exception)
01367     rb_iseq_t *iseq;                 // cmi
01368     VALUE magic;                     // C_METHOD_FRAME
01369     VALUE self;                      // ?
01370     VALUE *ep;                       // ep == lep
01371     rb_iseq_t * block_iseq;          //
01372     VALUE proc;                      // always 0
01373   };
01374 
01375   struct C_BLOCK_CONTROL_FRAME {
01376     VALUE *pc;                       // point only "finish" insn
01377     VALUE *sp;                       // sp
01378     rb_iseq_t *iseq;                 // ?
01379     VALUE magic;                     // C_METHOD_FRAME
01380     VALUE self;                      // needed?
01381     VALUE *ep;                       // ep
01382     rb_iseq_t * block_iseq; // 0
01383   };
01384  */
01385 
01386 
01387 static VALUE
01388 vm_exec(rb_thread_t *th)
01389 {
01390     int state;
01391     VALUE result, err;
01392     VALUE initial = 0;
01393 
01394     TH_PUSH_TAG(th);
01395     _tag.retval = Qnil;
01396     if ((state = EXEC_TAG()) == 0) {
01397       vm_loop_start:
01398         result = vm_exec_core(th, initial);
01399         if ((state = th->state) != 0) {
01400             err = result;
01401             th->state = 0;
01402             goto exception_handler;
01403         }
01404     }
01405     else {
01406         int i;
01407         struct iseq_catch_table_entry *entry;
01408         unsigned long epc, cont_pc, cont_sp;
01409         VALUE catch_iseqval;
01410         rb_control_frame_t *cfp;
01411         VALUE type;
01412         VALUE *escape_ep;
01413 
01414         err = th->errinfo;
01415 
01416       exception_handler:
01417         cont_pc = cont_sp = catch_iseqval = 0;
01418 
01419         while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
01420             if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
01421                 const rb_method_entry_t *me = th->cfp->me;
01422                 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil);
01423                 RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
01424             }
01425             th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
01426         }
01427 
01428         cfp = th->cfp;
01429         epc = cfp->pc - cfp->iseq->iseq_encoded;
01430 
01431         escape_ep = NULL;
01432         if (state == TAG_BREAK || state == TAG_RETURN) {
01433             escape_ep = GET_THROWOBJ_CATCH_POINT(err);
01434 
01435             if (cfp->ep == escape_ep) {
01436                 if (state == TAG_RETURN) {
01437                     if (!VM_FRAME_TYPE_FINISH_P(cfp)) {
01438                         SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->ep);
01439                         SET_THROWOBJ_STATE(err, state = TAG_BREAK);
01440                     }
01441                     else {
01442                         for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01443                             entry = &cfp->iseq->catch_table[i];
01444                             if (entry->start < epc && entry->end >= epc) {
01445                                 if (entry->type == CATCH_TYPE_ENSURE) {
01446                                     catch_iseqval = entry->iseq;
01447                                     cont_pc = entry->cont;
01448                                     cont_sp = entry->sp;
01449                                     break;
01450                                 }
01451                             }
01452                         }
01453                         if (!catch_iseqval) {
01454                             result = GET_THROWOBJ_VAL(err);
01455                             th->errinfo = Qnil;
01456 
01457                             switch (VM_FRAME_TYPE(cfp)) {
01458                               case VM_FRAME_MAGIC_LAMBDA:
01459                                 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
01460                                 break;
01461                             }
01462 
01463                             vm_pop_frame(th);
01464                             goto finish_vme;
01465                         }
01466                     }
01467                     /* through */
01468                 }
01469                 else {
01470                     /* TAG_BREAK */
01471 #if OPT_STACK_CACHING
01472                     initial = (GET_THROWOBJ_VAL(err));
01473 #else
01474                     *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
01475 #endif
01476                     th->errinfo = Qnil;
01477                     goto vm_loop_start;
01478                 }
01479             }
01480         }
01481 
01482         if (state == TAG_RAISE) {
01483             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01484                 entry = &cfp->iseq->catch_table[i];
01485                 if (entry->start < epc && entry->end >= epc) {
01486 
01487                     if (entry->type == CATCH_TYPE_RESCUE ||
01488                         entry->type == CATCH_TYPE_ENSURE) {
01489                         catch_iseqval = entry->iseq;
01490                         cont_pc = entry->cont;
01491                         cont_sp = entry->sp;
01492                         break;
01493                     }
01494                 }
01495             }
01496         }
01497         else if (state == TAG_RETRY) {
01498             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01499                 entry = &cfp->iseq->catch_table[i];
01500                 if (entry->start < epc && entry->end >= epc) {
01501 
01502                     if (entry->type == CATCH_TYPE_ENSURE) {
01503                         catch_iseqval = entry->iseq;
01504                         cont_pc = entry->cont;
01505                         cont_sp = entry->sp;
01506                         break;
01507                     }
01508                     else if (entry->type == CATCH_TYPE_RETRY) {
01509                         VALUE *escape_ep;
01510                         escape_ep = GET_THROWOBJ_CATCH_POINT(err);
01511                         if (cfp->ep == escape_ep) {
01512                             cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
01513                             th->errinfo = Qnil;
01514                             goto vm_loop_start;
01515                         }
01516                     }
01517                 }
01518             }
01519         }
01520         else if (state == TAG_BREAK && ((VALUE)escape_ep & ~0x03) == 0) {
01521             type = CATCH_TYPE_BREAK;
01522 
01523           search_restart_point:
01524             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01525                 entry = &cfp->iseq->catch_table[i];
01526 
01527                 if (entry->start < epc && entry->end >= epc) {
01528                     if (entry->type == CATCH_TYPE_ENSURE) {
01529                         catch_iseqval = entry->iseq;
01530                         cont_pc = entry->cont;
01531                         cont_sp = entry->sp;
01532                         break;
01533                     }
01534                     else if (entry->type == type) {
01535                         cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
01536                         cfp->sp = vm_base_ptr(cfp) + entry->sp;
01537 
01538                         if (state != TAG_REDO) {
01539 #if OPT_STACK_CACHING
01540                             initial = (GET_THROWOBJ_VAL(err));
01541 #else
01542                             *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
01543 #endif
01544                         }
01545                         th->errinfo = Qnil;
01546                         th->state = 0;
01547                         goto vm_loop_start;
01548                     }
01549                 }
01550             }
01551         }
01552         else if (state == TAG_REDO) {
01553             type = CATCH_TYPE_REDO;
01554             goto search_restart_point;
01555         }
01556         else if (state == TAG_NEXT) {
01557             type = CATCH_TYPE_NEXT;
01558             goto search_restart_point;
01559         }
01560         else {
01561             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01562                 entry = &cfp->iseq->catch_table[i];
01563                 if (entry->start < epc && entry->end >= epc) {
01564 
01565                     if (entry->type == CATCH_TYPE_ENSURE) {
01566                         catch_iseqval = entry->iseq;
01567                         cont_pc = entry->cont;
01568                         cont_sp = entry->sp;
01569                         break;
01570                     }
01571                 }
01572             }
01573         }
01574 
01575         if (catch_iseqval != 0) {
01576             /* found catch table */
01577             rb_iseq_t *catch_iseq;
01578 
01579             /* enter catch scope */
01580             GetISeqPtr(catch_iseqval, catch_iseq);
01581             cfp->sp = vm_base_ptr(cfp) + cont_sp;
01582             cfp->pc = cfp->iseq->iseq_encoded + cont_pc;
01583 
01584             /* push block frame */
01585             cfp->sp[0] = err;
01586             vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
01587                           cfp->self, cfp->klass,
01588                           VM_ENVVAL_PREV_EP_PTR(cfp->ep),
01589                           catch_iseq->iseq_encoded,
01590                           cfp->sp + 1 /* push value */,
01591                           catch_iseq->local_size - 1,
01592                           cfp->me, catch_iseq->stack_max);
01593 
01594             state = 0;
01595             th->state = 0;
01596             th->errinfo = Qnil;
01597             goto vm_loop_start;
01598         }
01599         else {
01600             /* skip frame */
01601 
01602             switch (VM_FRAME_TYPE(th->cfp)) {
01603               case VM_FRAME_MAGIC_METHOD:
01604                 RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0);
01605                 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil);
01606                 break;
01607               case VM_FRAME_MAGIC_BLOCK:
01608               case VM_FRAME_MAGIC_LAMBDA:
01609                 if (VM_FRAME_TYPE_BMETHOD_P(th->cfp)) {
01610                     EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
01611                     EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, th->cfp->me->called_id, th->cfp->me->klass, Qnil);
01612                 }
01613                 else {
01614                     EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
01615                 }
01616                 break;
01617               case VM_FRAME_MAGIC_CLASS:
01618                 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil);
01619                 break;
01620             }
01621 
01622             if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
01623                 vm_pop_frame(th);
01624                 th->errinfo = err;
01625                 TH_POP_TAG2();
01626                 JUMP_TAG(state);
01627             }
01628             else {
01629                 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
01630                 goto exception_handler;
01631             }
01632         }
01633     }
01634   finish_vme:
01635     TH_POP_TAG();
01636     return result;
01637 }
01638 
01639 /* misc */
01640 
01641 VALUE
01642 rb_iseq_eval(VALUE iseqval)
01643 {
01644     rb_thread_t *th = GET_THREAD();
01645     VALUE val;
01646 
01647     vm_set_top_stack(th, iseqval);
01648 
01649     val = vm_exec(th);
01650     RB_GC_GUARD(iseqval); /* prohibit tail call optimization */
01651     return val;
01652 }
01653 
01654 VALUE
01655 rb_iseq_eval_main(VALUE iseqval)
01656 {
01657     rb_thread_t *th = GET_THREAD();
01658     VALUE val;
01659 
01660     vm_set_main_stack(th, iseqval);
01661 
01662     val = vm_exec(th);
01663     RB_GC_GUARD(iseqval); /* prohibit tail call optimization */
01664     return val;
01665 }
01666 
01667 int
01668 rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
01669 {
01670     rb_iseq_t *iseq = cfp->iseq;
01671     if (!iseq && cfp->me) {
01672         if (idp) *idp = cfp->me->def->original_id;
01673         if (klassp) *klassp = cfp->me->klass;
01674         return 1;
01675     }
01676     while (iseq) {
01677         if (RUBY_VM_IFUNC_P(iseq)) {
01678             if (idp) *idp = idIFUNC;
01679             if (klassp) *klassp = 0;
01680             return 1;
01681         }
01682         if (iseq->defined_method_id) {
01683             if (idp) *idp = iseq->defined_method_id;
01684             if (klassp) *klassp = iseq->klass;
01685             return 1;
01686         }
01687         if (iseq->local_iseq == iseq) {
01688             break;
01689         }
01690         iseq = iseq->parent_iseq;
01691     }
01692     return 0;
01693 }
01694 
01695 int
01696 rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp)
01697 {
01698     return rb_vm_control_frame_id_and_class(th->cfp, idp, klassp);
01699 }
01700 
01701 int
01702 rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
01703 {
01704     return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp);
01705 }
01706 
01707 VALUE
01708 rb_thread_current_status(const rb_thread_t *th)
01709 {
01710     const rb_control_frame_t *cfp = th->cfp;
01711     VALUE str = Qnil;
01712 
01713     if (cfp->iseq != 0) {
01714         if (cfp->pc != 0) {
01715             rb_iseq_t *iseq = cfp->iseq;
01716             int line_no = rb_vm_get_sourceline(cfp);
01717             char *file = RSTRING_PTR(iseq->location.path);
01718             str = rb_sprintf("%s:%d:in `%s'",
01719                              file, line_no, RSTRING_PTR(iseq->location.label));
01720         }
01721     }
01722     else if (cfp->me->def->original_id) {
01723         str = rb_sprintf("`%s#%s' (cfunc)",
01724                          rb_class2name(cfp->me->klass),
01725                          rb_id2name(cfp->me->def->original_id));
01726     }
01727 
01728     return str;
01729 }
01730 
01731 VALUE
01732 rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
01733                  const rb_block_t *blockptr, VALUE filename)
01734 {
01735     rb_thread_t *th = GET_THREAD();
01736     const rb_control_frame_t *reg_cfp = th->cfp;
01737     volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
01738     VALUE val;
01739 
01740     vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
01741                   recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0, 0);
01742 
01743     val = (*func)(arg);
01744 
01745     vm_pop_frame(th);
01746     return val;
01747 }
01748 
01749 /* vm */
01750 
01751 static int
01752 vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy)
01753 {
01754     VALUE thval = (VALUE)key;
01755     rb_gc_mark(thval);
01756     return ST_CONTINUE;
01757 }
01758 
01759 void rb_vm_trace_mark_event_hooks(rb_hook_list_t *hooks);
01760 
01761 void
01762 rb_vm_mark(void *ptr)
01763 {
01764     int i;
01765 
01766     RUBY_MARK_ENTER("vm");
01767     RUBY_GC_INFO("-------------------------------------------------\n");
01768     if (ptr) {
01769         rb_vm_t *vm = ptr;
01770         if (vm->living_threads) {
01771             st_foreach(vm->living_threads, vm_mark_each_thread_func, 0);
01772         }
01773         RUBY_MARK_UNLESS_NULL(vm->thgroup_default);
01774         RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
01775         RUBY_MARK_UNLESS_NULL(vm->load_path);
01776         RUBY_MARK_UNLESS_NULL(vm->load_path_snapshot);
01777         RUBY_MARK_UNLESS_NULL(vm->load_path_check_cache);
01778         RUBY_MARK_UNLESS_NULL(vm->expanded_load_path);
01779         RUBY_MARK_UNLESS_NULL(vm->loaded_features);
01780         RUBY_MARK_UNLESS_NULL(vm->loaded_features_snapshot);
01781         RUBY_MARK_UNLESS_NULL(vm->top_self);
01782         RUBY_MARK_UNLESS_NULL(vm->coverages);
01783         RUBY_MARK_UNLESS_NULL(vm->defined_module_hash);
01784         rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count);
01785 
01786         if (vm->loading_table) {
01787             rb_mark_tbl(vm->loading_table);
01788         }
01789 
01790         rb_vm_trace_mark_event_hooks(&vm->event_hooks);
01791 
01792         for (i = 0; i < RUBY_NSIG; i++) {
01793             if (vm->trap_list[i].cmd)
01794                 rb_gc_mark(vm->trap_list[i].cmd);
01795         }
01796         if (vm->defined_strings) {
01797             rb_gc_mark_locations(vm->defined_strings, vm->defined_strings + DEFINED_EXPR);
01798         }
01799     }
01800 
01801     RUBY_MARK_LEAVE("vm");
01802 }
01803 
01804 
01805 int
01806 rb_vm_add_root_module(ID id, VALUE module)
01807 {
01808     rb_vm_t *vm = GET_VM();
01809     if (vm->defined_module_hash) {
01810         rb_hash_aset(vm->defined_module_hash, ID2SYM(id), module);
01811     }
01812     return TRUE;
01813 }
01814 
01815 #define vm_free 0
01816 
01817 int
01818 ruby_vm_destruct(rb_vm_t *vm)
01819 {
01820     RUBY_FREE_ENTER("vm");
01821     if (vm) {
01822         rb_thread_t *th = vm->main_thread;
01823 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
01824         struct rb_objspace *objspace = vm->objspace;
01825 #endif
01826         rb_gc_force_recycle(vm->self);
01827         vm->main_thread = 0;
01828         if (th) {
01829             rb_fiber_reset_root_local_storage(th->self);
01830             thread_free(th);
01831         }
01832         if (vm->living_threads) {
01833             st_free_table(vm->living_threads);
01834             vm->living_threads = 0;
01835         }
01836         ruby_vm_run_at_exit_hooks(vm);
01837         rb_vm_gvl_destroy(vm);
01838 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
01839         if (objspace) {
01840             rb_objspace_free(objspace);
01841         }
01842 #endif
01843         /* after freeing objspace, you *can't* use ruby_xfree() */
01844         ruby_mimfree(vm);
01845         ruby_current_vm = 0;
01846     }
01847     RUBY_FREE_LEAVE("vm");
01848     return 0;
01849 }
01850 
01851 static size_t
01852 vm_memsize(const void *ptr)
01853 {
01854     if (ptr) {
01855         const rb_vm_t *vmobj = ptr;
01856         size_t size = sizeof(rb_vm_t);
01857         if (vmobj->living_threads) {
01858             size += st_memsize(vmobj->living_threads);
01859         }
01860         if (vmobj->defined_strings) {
01861             size += DEFINED_EXPR * sizeof(VALUE);
01862         }
01863         return size;
01864     }
01865     else {
01866         return 0;
01867     }
01868 }
01869 
01870 static const rb_data_type_t vm_data_type = {
01871     "VM",
01872     {rb_vm_mark, vm_free, vm_memsize,},
01873     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01874 };
01875 
01876 
01877 static VALUE
01878 vm_default_params(void)
01879 {
01880     rb_vm_t *vm = GET_VM();
01881     VALUE result = rb_hash_new();
01882 #define SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), SIZET2NUM(vm->default_params.name));
01883     SET(thread_vm_stack_size);
01884     SET(thread_machine_stack_size);
01885     SET(fiber_vm_stack_size);
01886     SET(fiber_machine_stack_size);
01887 #undef SET
01888     rb_obj_freeze(result);
01889     return result;
01890 }
01891 
01892 static size_t
01893 get_param(const char *name, size_t default_value, size_t min_value)
01894 {
01895     const char *envval;
01896     size_t result = default_value;
01897     if ((envval = getenv(name)) != 0) {
01898         long val = atol(envval);
01899         if (val < (long)min_value) {
01900             val = (long)min_value;
01901         }
01902         result = (size_t)(((val -1 + RUBY_VM_SIZE_ALIGN) / RUBY_VM_SIZE_ALIGN) * RUBY_VM_SIZE_ALIGN);
01903     }
01904     if (0) fprintf(stderr, "%s: %"PRIdSIZE"\n", name, result); /* debug print */
01905 
01906     return result;
01907 }
01908 
01909 static void
01910 check_machine_stack_size(size_t *sizep)
01911 {
01912 #ifdef PTHREAD_STACK_MIN
01913     size_t size = *sizep;
01914 #endif
01915 
01916 #ifdef __SYMBIAN32__
01917     *sizep = 64 * 1024; /* 64KB: Let's be slightly more frugal on mobile platform */
01918 #endif
01919 
01920 #ifdef PTHREAD_STACK_MIN
01921     if (size < PTHREAD_STACK_MIN) {
01922         *sizep = PTHREAD_STACK_MIN * 2;
01923     }
01924 #endif
01925 }
01926 
01927 static void
01928 vm_default_params_setup(rb_vm_t *vm)
01929 {
01930     vm->default_params.thread_vm_stack_size =
01931       get_param("RUBY_THREAD_VM_STACK_SIZE",
01932                 RUBY_VM_THREAD_VM_STACK_SIZE,
01933                 RUBY_VM_THREAD_VM_STACK_SIZE_MIN);
01934 
01935     vm->default_params.thread_machine_stack_size =
01936       get_param("RUBY_THREAD_MACHINE_STACK_SIZE",
01937                 RUBY_VM_THREAD_MACHINE_STACK_SIZE,
01938                 RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN);
01939 
01940     vm->default_params.fiber_vm_stack_size =
01941       get_param("RUBY_FIBER_VM_STACK_SIZE",
01942                 RUBY_VM_FIBER_VM_STACK_SIZE,
01943                 RUBY_VM_FIBER_VM_STACK_SIZE_MIN);
01944 
01945     vm->default_params.fiber_machine_stack_size =
01946       get_param("RUBY_FIBER_MACHINE_STACK_SIZE",
01947                 RUBY_VM_FIBER_MACHINE_STACK_SIZE,
01948                 RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN);
01949 
01950     /* environment dependent check */
01951     check_machine_stack_size(&vm->default_params.thread_machine_stack_size);
01952     check_machine_stack_size(&vm->default_params.fiber_machine_stack_size);
01953 }
01954 
01955 static void
01956 vm_init2(rb_vm_t *vm)
01957 {
01958     MEMZERO(vm, rb_vm_t, 1);
01959     vm->src_encoding_index = -1;
01960     vm->at_exit.basic.flags = (T_ARRAY | RARRAY_EMBED_FLAG) & ~RARRAY_EMBED_LEN_MASK; /* len set 0 */
01961     rb_obj_hide((VALUE)&vm->at_exit);
01962 
01963     vm_default_params_setup(vm);
01964 }
01965 
01966 /* Thread */
01967 
01968 #define USE_THREAD_DATA_RECYCLE 1
01969 
01970 #if USE_THREAD_DATA_RECYCLE
01971 #define RECYCLE_MAX 64
01972 static VALUE *thread_recycle_stack_slot[RECYCLE_MAX];
01973 static int thread_recycle_stack_count = 0;
01974 
01975 static VALUE *
01976 thread_recycle_stack(size_t size)
01977 {
01978     if (thread_recycle_stack_count) {
01979         /* TODO: check stack size if stack sizes are variable */
01980         return thread_recycle_stack_slot[--thread_recycle_stack_count];
01981     }
01982     else {
01983         return ALLOC_N(VALUE, size);
01984     }
01985 }
01986 
01987 #else
01988 #define thread_recycle_stack(size) ALLOC_N(VALUE, (size))
01989 #endif
01990 
01991 void
01992 rb_thread_recycle_stack_release(VALUE *stack)
01993 {
01994 #if USE_THREAD_DATA_RECYCLE
01995     if (thread_recycle_stack_count < RECYCLE_MAX) {
01996         thread_recycle_stack_slot[thread_recycle_stack_count++] = stack;
01997         return;
01998     }
01999 #endif
02000     ruby_xfree(stack);
02001 }
02002 
02003 #ifdef USE_THREAD_RECYCLE
02004 static rb_thread_t *
02005 thread_recycle_struct(void)
02006 {
02007     void *p = ALLOC_N(rb_thread_t, 1);
02008     memset(p, 0, sizeof(rb_thread_t));
02009     return p;
02010 }
02011 #endif
02012 
02013 void
02014 rb_thread_mark(void *ptr)
02015 {
02016     rb_thread_t *th = NULL;
02017     RUBY_MARK_ENTER("thread");
02018     if (ptr) {
02019         th = ptr;
02020         if (th->stack) {
02021             VALUE *p = th->stack;
02022             VALUE *sp = th->cfp->sp;
02023             rb_control_frame_t *cfp = th->cfp;
02024             rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
02025 
02026             while (p < sp) {
02027                 rb_gc_mark(*p++);
02028             }
02029             rb_gc_mark_locations(p, p + th->mark_stack_len);
02030 
02031             while (cfp != limit_cfp) {
02032                 rb_iseq_t *iseq = cfp->iseq;
02033                 rb_gc_mark(cfp->proc);
02034                 rb_gc_mark(cfp->self);
02035                 rb_gc_mark(cfp->klass);
02036                 if (iseq) {
02037                     rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq);
02038                 }
02039                 if (cfp->me) {
02040                     /* TODO: marking `me' can be more sophisticated way */
02041                     ((rb_method_entry_t *)cfp->me)->mark = 1;
02042                     rb_mark_method_entry(cfp->me);
02043                 }
02044                 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
02045             }
02046         }
02047 
02048         /* mark ruby objects */
02049         RUBY_MARK_UNLESS_NULL(th->first_proc);
02050         if (th->first_proc) RUBY_MARK_UNLESS_NULL(th->first_args);
02051 
02052         RUBY_MARK_UNLESS_NULL(th->thgroup);
02053         RUBY_MARK_UNLESS_NULL(th->value);
02054         RUBY_MARK_UNLESS_NULL(th->errinfo);
02055         RUBY_MARK_UNLESS_NULL(th->pending_interrupt_queue);
02056         RUBY_MARK_UNLESS_NULL(th->pending_interrupt_mask_stack);
02057         RUBY_MARK_UNLESS_NULL(th->root_svar);
02058         RUBY_MARK_UNLESS_NULL(th->top_self);
02059         RUBY_MARK_UNLESS_NULL(th->top_wrapper);
02060         RUBY_MARK_UNLESS_NULL(th->fiber);
02061         RUBY_MARK_UNLESS_NULL(th->root_fiber);
02062         RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
02063         RUBY_MARK_UNLESS_NULL(th->last_status);
02064 
02065         RUBY_MARK_UNLESS_NULL(th->locking_mutex);
02066 
02067         rb_mark_tbl(th->local_storage);
02068 
02069         if (GET_THREAD() != th && th->machine.stack_start && th->machine.stack_end) {
02070             rb_gc_mark_machine_stack(th);
02071             rb_gc_mark_locations((VALUE *)&th->machine.regs,
02072                                  (VALUE *)(&th->machine.regs) +
02073                                  sizeof(th->machine.regs) / sizeof(VALUE));
02074         }
02075 
02076         rb_vm_trace_mark_event_hooks(&th->event_hooks);
02077     }
02078 
02079     RUBY_MARK_LEAVE("thread");
02080 }
02081 
02082 static void
02083 thread_free(void *ptr)
02084 {
02085     rb_thread_t *th;
02086     RUBY_FREE_ENTER("thread");
02087 
02088     if (ptr) {
02089         th = ptr;
02090 
02091         if (!th->root_fiber) {
02092             RUBY_FREE_UNLESS_NULL(th->stack);
02093         }
02094 
02095         if (th->locking_mutex != Qfalse) {
02096             rb_bug("thread_free: locking_mutex must be NULL (%p:%p)", (void *)th, (void *)th->locking_mutex);
02097         }
02098         if (th->keeping_mutexes != NULL) {
02099             rb_bug("thread_free: keeping_mutexes must be NULL (%p:%p)", (void *)th, (void *)th->keeping_mutexes);
02100         }
02101 
02102         if (th->local_storage) {
02103             st_free_table(th->local_storage);
02104         }
02105 
02106         if (th->vm && th->vm->main_thread == th) {
02107             RUBY_GC_INFO("main thread\n");
02108         }
02109         else {
02110 #ifdef USE_SIGALTSTACK
02111             if (th->altstack) {
02112                 free(th->altstack);
02113             }
02114 #endif
02115             ruby_xfree(ptr);
02116         }
02117         if (ruby_current_thread == th)
02118             ruby_current_thread = NULL;
02119     }
02120     RUBY_FREE_LEAVE("thread");
02121 }
02122 
02123 static size_t
02124 thread_memsize(const void *ptr)
02125 {
02126     if (ptr) {
02127         const rb_thread_t *th = ptr;
02128         size_t size = sizeof(rb_thread_t);
02129 
02130         if (!th->root_fiber) {
02131             size += th->stack_size * sizeof(VALUE);
02132         }
02133         if (th->local_storage) {
02134             size += st_memsize(th->local_storage);
02135         }
02136         return size;
02137     }
02138     else {
02139         return 0;
02140     }
02141 }
02142 
02143 #define thread_data_type ruby_threadptr_data_type
02144 const rb_data_type_t ruby_threadptr_data_type = {
02145     "VM/thread",
02146     {
02147         rb_thread_mark,
02148         thread_free,
02149         thread_memsize,
02150     },
02151     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
02152 };
02153 
02154 VALUE
02155 rb_obj_is_thread(VALUE obj)
02156 {
02157     if (rb_typeddata_is_kind_of(obj, &thread_data_type)) {
02158         return Qtrue;
02159     }
02160     else {
02161         return Qfalse;
02162     }
02163 }
02164 
02165 static VALUE
02166 thread_alloc(VALUE klass)
02167 {
02168     VALUE volatile obj;
02169 #ifdef USE_THREAD_RECYCLE
02170     rb_thread_t *th = thread_recycle_struct();
02171     obj = TypedData_Wrap_Struct(klass, &thread_data_type, th);
02172 #else
02173     rb_thread_t *th;
02174     obj = TypedData_Make_Struct(klass, rb_thread_t, &thread_data_type, th);
02175 #endif
02176     return obj;
02177 }
02178 
02179 static void
02180 th_init(rb_thread_t *th, VALUE self)
02181 {
02182     th->self = self;
02183 
02184     /* allocate thread stack */
02185 #ifdef USE_SIGALTSTACK
02186     /* altstack of main thread is reallocated in another place */
02187     th->altstack = malloc(rb_sigaltstack_size());
02188 #endif
02189     /* th->stack_size is word number.
02190      * th->vm->default_params.thread_vm_stack_size is byte size.
02191      */
02192     th->stack_size = th->vm->default_params.thread_vm_stack_size / sizeof(VALUE);
02193     th->stack = thread_recycle_stack(th->stack_size);
02194 
02195     th->cfp = (void *)(th->stack + th->stack_size);
02196 
02197     vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
02198                   Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0, 0);
02199 
02200     th->status = THREAD_RUNNABLE;
02201     th->errinfo = Qnil;
02202     th->last_status = Qnil;
02203     th->waiting_fd = -1;
02204     th->root_svar = Qnil;
02205 
02206 #if OPT_CALL_THREADED_CODE
02207     th->retval = Qundef;
02208 #endif
02209 }
02210 
02211 static VALUE
02212 ruby_thread_init(VALUE self)
02213 {
02214     rb_thread_t *th;
02215     rb_vm_t *vm = GET_THREAD()->vm;
02216     GetThreadPtr(self, th);
02217 
02218     th->vm = vm;
02219     th_init(th, self);
02220     rb_ivar_set(self, rb_intern("locals"), rb_hash_new());
02221 
02222     th->top_wrapper = 0;
02223     th->top_self = rb_vm_top_self();
02224     th->root_svar = Qnil;
02225     return self;
02226 }
02227 
02228 VALUE
02229 rb_thread_alloc(VALUE klass)
02230 {
02231     VALUE self = thread_alloc(klass);
02232     ruby_thread_init(self);
02233     return self;
02234 }
02235 
02236 static void
02237 vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
02238                  rb_num_t is_singleton, NODE *cref)
02239 {
02240     VALUE klass = cref->nd_clss;
02241     int noex = (int)cref->nd_visi;
02242     rb_iseq_t *miseq;
02243     GetISeqPtr(iseqval, miseq);
02244 
02245     if (miseq->klass) {
02246         RB_GC_GUARD(iseqval) = rb_iseq_clone(iseqval, 0);
02247         GetISeqPtr(iseqval, miseq);
02248     }
02249 
02250     if (NIL_P(klass)) {
02251         rb_raise(rb_eTypeError, "no class/module to add method");
02252     }
02253 
02254     if (is_singleton) {
02255         klass = rb_singleton_class(obj); /* class and frozen checked in this API */
02256         noex = NOEX_PUBLIC;
02257     }
02258 
02259     /* dup */
02260     COPY_CREF(miseq->cref_stack, cref);
02261     miseq->cref_stack->nd_visi = NOEX_PUBLIC;
02262     RB_OBJ_WRITE(miseq->self, &miseq->klass, klass);
02263     miseq->defined_method_id = id;
02264     rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
02265 
02266     if (!is_singleton && noex == NOEX_MODFUNC) {
02267         klass = rb_singleton_class(klass);
02268         rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
02269     }
02270 }
02271 
02272 #define REWIND_CFP(expr) do { \
02273     rb_thread_t *th__ = GET_THREAD(); \
02274     th__->cfp++; expr; th__->cfp--; \
02275 } while (0)
02276 
02277 static VALUE
02278 m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
02279 {
02280     REWIND_CFP({
02281         vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
02282     });
02283     return sym;
02284 }
02285 
02286 static VALUE
02287 m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
02288 {
02289     REWIND_CFP({
02290         vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
02291     });
02292     return sym;
02293 }
02294 
02295 static VALUE
02296 m_core_set_method_alias(VALUE self, VALUE cbase, VALUE sym1, VALUE sym2)
02297 {
02298     REWIND_CFP({
02299         rb_alias(cbase, SYM2ID(sym1), SYM2ID(sym2));
02300     });
02301     return Qnil;
02302 }
02303 
02304 static VALUE
02305 m_core_set_variable_alias(VALUE self, VALUE sym1, VALUE sym2)
02306 {
02307     REWIND_CFP({
02308         rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
02309     });
02310     return Qnil;
02311 }
02312 
02313 static VALUE
02314 m_core_undef_method(VALUE self, VALUE cbase, VALUE sym)
02315 {
02316     REWIND_CFP({
02317         rb_undef(cbase, SYM2ID(sym));
02318         rb_clear_method_cache_by_class(self);
02319     });
02320     return Qnil;
02321 }
02322 
02323 static VALUE
02324 m_core_set_postexe(VALUE self)
02325 {
02326     rb_set_end_proc(rb_call_end_proc, rb_block_proc());
02327     return Qnil;
02328 }
02329 
02330 static VALUE core_hash_merge_ary(VALUE hash, VALUE ary);
02331 static VALUE core_hash_from_ary(VALUE ary);
02332 static VALUE core_hash_merge_kwd(int argc, VALUE *argv);
02333 
02334 static VALUE
02335 core_hash_merge(VALUE hash, long argc, const VALUE *argv)
02336 {
02337     long i;
02338 
02339     assert(argc % 2 == 0);
02340     for (i=0; i<argc; i+=2) {
02341         rb_hash_aset(hash, argv[i], argv[i+1]);
02342     }
02343     return hash;
02344 }
02345 
02346 static VALUE
02347 m_core_hash_from_ary(VALUE self, VALUE ary)
02348 {
02349     VALUE hash;
02350     REWIND_CFP(hash = core_hash_from_ary(ary));
02351     return hash;
02352 }
02353 
02354 static VALUE
02355 core_hash_from_ary(VALUE ary)
02356 {
02357     VALUE hash = rb_hash_new();
02358 
02359     if (RUBY_DTRACE_HASH_CREATE_ENABLED()) {
02360         RUBY_DTRACE_HASH_CREATE(RARRAY_LEN(ary), rb_sourcefile(), rb_sourceline());
02361     }
02362 
02363     return core_hash_merge_ary(hash, ary);
02364 }
02365 
02366 static VALUE
02367 m_core_hash_merge_ary(VALUE self, VALUE hash, VALUE ary)
02368 {
02369     REWIND_CFP(core_hash_merge_ary(hash, ary));
02370     return hash;
02371 }
02372 
02373 static VALUE
02374 core_hash_merge_ary(VALUE hash, VALUE ary)
02375 {
02376     core_hash_merge(hash, RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
02377     return hash;
02378 }
02379 
02380 static VALUE
02381 m_core_hash_merge_ptr(int argc, VALUE *argv, VALUE recv)
02382 {
02383     VALUE hash = argv[0];
02384 
02385     REWIND_CFP(core_hash_merge(hash, argc-1, argv+1));
02386 
02387     return hash;
02388 }
02389 
02390 static int
02391 kwmerge_ii(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
02392 {
02393     if (existing) return ST_STOP;
02394     *value = arg;
02395     return ST_CONTINUE;
02396 }
02397 
02398 static int
02399 kwmerge_i(VALUE key, VALUE value, VALUE hash)
02400 {
02401     if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL);
02402     if (st_update(RHASH_TBL_RAW(hash), key, kwmerge_ii, (st_data_t)value) == 0) { /* !existing */
02403         RB_OBJ_WRITTEN(hash, Qundef, value);
02404     }
02405     return ST_CONTINUE;
02406 }
02407 
02408 static int
02409 kwcheck_i(VALUE key, VALUE value, VALUE hash)
02410 {
02411     if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL);
02412     return ST_CONTINUE;
02413 }
02414 
02415 static VALUE
02416 m_core_hash_merge_kwd(int argc, VALUE *argv, VALUE recv)
02417 {
02418     VALUE hash;
02419     REWIND_CFP(hash = core_hash_merge_kwd(argc, argv));
02420     return hash;
02421 }
02422 
02423 static VALUE
02424 core_hash_merge_kwd(int argc, VALUE *argv)
02425 {
02426     VALUE hash, kw;
02427     rb_check_arity(argc, 1, 2);
02428     hash = argv[0];
02429     kw = argv[argc-1];
02430     kw = rb_convert_type(kw, T_HASH, "Hash", "to_hash");
02431     if (argc < 2) hash = kw;
02432     rb_hash_foreach(kw, argc < 2 ? kwcheck_i : kwmerge_i, hash);
02433     return hash;
02434 }
02435 
02436 extern VALUE *rb_gc_stack_start;
02437 extern size_t rb_gc_stack_maxsize;
02438 #ifdef __ia64
02439 extern VALUE *rb_gc_register_stack_start;
02440 #endif
02441 
02442 /* debug functions */
02443 
02444 /* :nodoc: */
02445 static VALUE
02446 sdr(void)
02447 {
02448     rb_vm_bugreport();
02449     return Qnil;
02450 }
02451 
02452 /* :nodoc: */
02453 static VALUE
02454 nsdr(void)
02455 {
02456     VALUE ary = rb_ary_new();
02457 #if HAVE_BACKTRACE
02458 #include <execinfo.h>
02459 #define MAX_NATIVE_TRACE 1024
02460     static void *trace[MAX_NATIVE_TRACE];
02461     int n = backtrace(trace, MAX_NATIVE_TRACE);
02462     char **syms = backtrace_symbols(trace, n);
02463     int i;
02464 
02465     if (syms == 0) {
02466         rb_memerror();
02467     }
02468 
02469     for (i=0; i<n; i++) {
02470         rb_ary_push(ary, rb_str_new2(syms[i]));
02471     }
02472     free(syms); /* OK */
02473 #endif
02474     return ary;
02475 }
02476 
02477 #if VM_COLLECT_USAGE_DETAILS
02478 static VALUE usage_analysis_insn_stop(VALUE self);
02479 static VALUE usage_analysis_operand_stop(VALUE self);
02480 static VALUE usage_analysis_register_stop(VALUE self);
02481 #endif
02482 
02483 void
02484 Init_VM(void)
02485 {
02486     VALUE opts;
02487     VALUE klass;
02488     VALUE fcore;
02489 
02490     /* ::RubyVM */
02491     rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);
02492     rb_undef_alloc_func(rb_cRubyVM);
02493     rb_undef_method(CLASS_OF(rb_cRubyVM), "new");
02494     rb_define_singleton_method(rb_cRubyVM, "stat", vm_stat, -1);
02495 
02496     /* FrozenCore (hidden) */
02497     fcore = rb_class_new(rb_cBasicObject);
02498     RBASIC(fcore)->flags = T_ICLASS;
02499     klass = rb_singleton_class(fcore);
02500     rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
02501     rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
02502     rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
02503     rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
02504     rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
02505     rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 0);
02506     rb_define_method_id(klass, id_core_hash_from_ary, m_core_hash_from_ary, 1);
02507     rb_define_method_id(klass, id_core_hash_merge_ary, m_core_hash_merge_ary, 2);
02508     rb_define_method_id(klass, id_core_hash_merge_ptr, m_core_hash_merge_ptr, -1);
02509     rb_define_method_id(klass, id_core_hash_merge_kwd, m_core_hash_merge_kwd, -1);
02510     rb_define_method_id(klass, idProc, rb_block_proc, 0);
02511     rb_define_method_id(klass, idLambda, rb_block_lambda, 0);
02512     rb_obj_freeze(fcore);
02513     RBASIC_CLEAR_CLASS(klass);
02514     RCLASS_SET_SUPER(klass, 0);
02515     rb_obj_freeze(klass);
02516     rb_gc_register_mark_object(fcore);
02517     rb_mRubyVMFrozenCore = fcore;
02518 
02519     /* ::RubyVM::Env */
02520     rb_cEnv = rb_define_class_under(rb_cRubyVM, "Env", rb_cObject);
02521     rb_undef_alloc_func(rb_cEnv);
02522     rb_undef_method(CLASS_OF(rb_cEnv), "new");
02523 
02524     /*
02525      * Document-class: Thread
02526      *
02527      *  Threads are the Ruby implementation for a concurrent programming model.
02528      *
02529      *  Programs that require multiple threads of execution are a perfect
02530      *  candidate for Ruby's Thread class.
02531      *
02532      *  For example, we can create a new thread separate from the main thread's
02533      *  execution using ::new.
02534      *
02535      *      thr = Thread.new { puts "Whats the big deal" }
02536      *
02537      *  Then we are able to pause the execution of the main thread and allow
02538      *  our new thread to finish, using #join:
02539      *
02540      *      thr.join #=> "Whats the big deal"
02541      *
02542      *  If we don't call +thr.join+ before the main thread terminates, then all
02543      *  other threads including +thr+ will be killed.
02544      *
02545      *  Alternatively, you can use an array for handling multiple threads at
02546      *  once, like in the following example:
02547      *
02548      *      threads = []
02549      *      threads << Thread.new { puts "Whats the big deal" }
02550      *      threads << Thread.new { 3.times { puts "Threads are fun!" } }
02551      *
02552      *  After creating a few threads we wait for them all to finish
02553      *  consecutively.
02554      *
02555      *      threads.each { |thr| thr.join }
02556      *
02557      *  === Thread initialization
02558      *
02559      *  In order to create new threads, Ruby provides ::new, ::start, and
02560      *  ::fork. A block must be provided with each of these methods, otherwise
02561      *  a ThreadError will be raised.
02562      *
02563      *  When subclassing the Thread class, the +initialize+ method of your
02564      *  subclass will be ignored by ::start and ::fork. Otherwise, be sure to
02565      *  call super in your +initialize+ method.
02566      *
02567      *  === Thread termination
02568      *
02569      *  For terminating threads, Ruby provides a variety of ways to do this.
02570      *
02571      *  The class method ::kill, is meant to exit a given thread:
02572      *
02573      *      thr = Thread.new { ... }
02574      *      Thread.kill(thr) # sends exit() to thr
02575      *
02576      *  Alternatively, you can use the instance method #exit, or any of its
02577      *  aliases #kill or #terminate.
02578      *
02579      *      thr.exit
02580      *
02581      *  === Thread status
02582      *
02583      *  Ruby provides a few instance methods for querying the state of a given
02584      *  thread. To get a string with the current thread's state use #status
02585      *
02586      *      thr = Thread.new { sleep }
02587      *      thr.status # => "sleep"
02588      *      thr.exit
02589      *      thr.status # => false
02590      *
02591      *  You can also use #alive? to tell if the thread is running or sleeping,
02592      *  and #stop? if the thread is dead or sleeping.
02593      *
02594      *  === Thread variables and scope
02595      *
02596      *  Since threads are created with blocks, the same rules apply to other
02597      *  Ruby blocks for variable scope. Any local variables created within this
02598      *  block are accessible to only this thread.
02599      *
02600      *  ==== Fiber-local vs. Thread-local
02601      *
02602      *  Each fiber has its own bucket for Thread#[] storage. When you set a
02603      *  new fiber-local it is only accessible within this Fiber. To illustrate:
02604      *
02605      *      Thread.new {
02606      *        Thread.current[:foo] = "bar"
02607      *        Fiber.new {
02608      *          p Thread.current[:foo] # => nil
02609      *        }.resume
02610      *      }.join
02611      *
02612      *  This example uses #[] for getting and #[]= for setting fiber-locals,
02613      *  you can also use #keys to list the fiber-locals for a given
02614      *  thread and #key? to check if a fiber-local exists.
02615      *
02616      *  When it comes to thread-locals, they are accessible within the entire
02617      *  scope of the thread. Given the following example:
02618      *
02619      *      Thread.new{
02620      *        Thread.current.thread_variable_set(:foo, 1)
02621      *        p Thread.current.thread_variable_get(:foo) # => 1
02622      *        Fiber.new{
02623      *          Thread.current.thread_variable_set(:foo, 2)
02624      *          p Thread.current.thread_variable_get(:foo) # => 2
02625      *        }.resume
02626      *        p Thread.current.thread_variable_get(:foo)   # => 2
02627      *      }.join
02628      *
02629      *  You can see that the thread-local +:foo+ carried over into the fiber
02630      *  and was changed to +2+ by the end of the thread.
02631      *
02632      *  This example makes use of #thread_variable_set to create new
02633      *  thread-locals, and #thread_variable_get to reference them.
02634      *
02635      *  There is also #thread_variables to list all thread-locals, and
02636      *  #thread_variable? to check if a given thread-local exists.
02637      *
02638      *  === Exception handling
02639      *
02640      *  Any thread can raise an exception using the #raise instance method,
02641      *  which operates similarly to Kernel#raise.
02642      *
02643      *  However, it's important to note that an exception that occurs in any
02644      *  thread except the main thread depends on #abort_on_exception. This
02645      *  option is +false+ by default, meaning that any unhandled exception will
02646      *  cause the thread to terminate silently when waited on by either #join
02647      *  or #value. You can change this default by either #abort_on_exception=
02648      *  +true+ or setting $DEBUG to +true+.
02649      *
02650      *  With the addition of the class method ::handle_interrupt, you can now
02651      *  handle exceptions asynchronously with threads.
02652      *
02653      *  === Scheduling
02654      *
02655      *  Ruby provides a few ways to support scheduling threads in your program.
02656      *
02657      *  The first way is by using the class method ::stop, to put the current
02658      *  running thread to sleep and schedule the execution of another thread.
02659      *
02660      *  Once a thread is asleep, you can use the instance method #wakeup to
02661      *  mark your thread as eligible for scheduling.
02662      *
02663      *  You can also try ::pass, which attempts to pass execution to another
02664      *  thread but is dependent on the OS whether a running thread will switch
02665      *  or not. The same goes for #priority, which lets you hint to the thread
02666      *  scheduler which threads you want to take precedence when passing
02667      *  execution. This method is also dependent on the OS and may be ignored
02668      *  on some platforms.
02669      *
02670      */
02671     rb_cThread = rb_define_class("Thread", rb_cObject);
02672     rb_undef_alloc_func(rb_cThread);
02673 
02674 #if VM_COLLECT_USAGE_DETAILS
02675     /* ::RubyVM::USAGE_ANALYSIS_* */
02676 #define define_usage_analysis_hash(name) /* shut up rdoc -C */ \
02677     rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_"#name, rb_hash_new())
02678     define_usage_analysis_hash("INSN");
02679     define_usage_analysis_hash("REGS");
02680     define_usage_analysis_hash("INSN_BIGRAM");
02681 
02682     rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_STOP", usage_analysis_insn_stop, 0);
02683     rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_STOP", usage_analysis_operand_stop, 0);
02684     rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_STOP", usage_analysis_register_stop, 0);
02685 #endif
02686 
02687     /* ::RubyVM::OPTS, which shows vm build options */
02688     rb_define_const(rb_cRubyVM, "OPTS", opts = rb_ary_new());
02689 
02690 #if   OPT_DIRECT_THREADED_CODE
02691     rb_ary_push(opts, rb_str_new2("direct threaded code"));
02692 #elif OPT_TOKEN_THREADED_CODE
02693     rb_ary_push(opts, rb_str_new2("token threaded code"));
02694 #elif OPT_CALL_THREADED_CODE
02695     rb_ary_push(opts, rb_str_new2("call threaded code"));
02696 #endif
02697 
02698 #if OPT_STACK_CACHING
02699     rb_ary_push(opts, rb_str_new2("stack caching"));
02700 #endif
02701 #if OPT_OPERANDS_UNIFICATION
02702     rb_ary_push(opts, rb_str_new2("operands unification]"));
02703 #endif
02704 #if OPT_INSTRUCTIONS_UNIFICATION
02705     rb_ary_push(opts, rb_str_new2("instructions unification"));
02706 #endif
02707 #if OPT_INLINE_METHOD_CACHE
02708     rb_ary_push(opts, rb_str_new2("inline method cache"));
02709 #endif
02710 #if OPT_BLOCKINLINING
02711     rb_ary_push(opts, rb_str_new2("block inlining"));
02712 #endif
02713 
02714     /* ::RubyVM::INSTRUCTION_NAMES */
02715     rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", rb_insns_name_array());
02716 
02717     /* ::RubyVM::DEFAULT_PARAMS
02718      * This constant variable shows VM's default parameters.
02719      * Note that changing these values does not affect VM execution.
02720      * Specification is not stable and you should not depend on this value.
02721      * Of course, this constant is MRI specific.
02722      */
02723     rb_define_const(rb_cRubyVM, "DEFAULT_PARAMS", vm_default_params());
02724 
02725     /* debug functions ::RubyVM::SDR(), ::RubyVM::NSDR() */
02726 #if VMDEBUG
02727     rb_define_singleton_method(rb_cRubyVM, "SDR", sdr, 0);
02728     rb_define_singleton_method(rb_cRubyVM, "NSDR", nsdr, 0);
02729 #else
02730     (void)sdr;
02731     (void)nsdr;
02732 #endif
02733 
02734     /* VM bootstrap: phase 2 */
02735     {
02736         rb_vm_t *vm = ruby_current_vm;
02737         rb_thread_t *th = GET_THREAD();
02738         VALUE filename = rb_str_new2("<main>");
02739         volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
02740         volatile VALUE th_self;
02741         rb_iseq_t *iseq;
02742 
02743         /* create vm object */
02744         vm->self = TypedData_Wrap_Struct(rb_cRubyVM, &vm_data_type, vm);
02745 
02746         /* create main thread */
02747         th_self = th->self = TypedData_Wrap_Struct(rb_cThread, &thread_data_type, th);
02748         rb_iv_set(th_self, "locals", rb_hash_new());
02749         vm->main_thread = th;
02750         vm->running_thread = th;
02751         th->vm = vm;
02752         th->top_wrapper = 0;
02753         th->top_self = rb_vm_top_self();
02754         rb_thread_set_current(th);
02755 
02756         vm->living_threads = st_init_numtable();
02757         st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id);
02758 
02759         rb_gc_register_mark_object(iseqval);
02760         GetISeqPtr(iseqval, iseq);
02761         th->cfp->iseq = iseq;
02762         th->cfp->pc = iseq->iseq_encoded;
02763         th->cfp->self = th->top_self;
02764         th->cfp->klass = Qnil;
02765 
02766         /*
02767          * The Binding of the top level scope
02768          */
02769         rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
02770     }
02771     vm_init_redefined_flag();
02772 
02773     /* vm_backtrace.c */
02774     Init_vm_backtrace();
02775     VM_PROFILE_ATEXIT();
02776 }
02777 
02778 void
02779 rb_vm_set_progname(VALUE filename)
02780 {
02781     rb_thread_t *th = GET_VM()->main_thread;
02782     rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
02783     --cfp;
02784     RB_OBJ_WRITE(cfp->iseq->self, &cfp->iseq->location.path, filename);
02785 }
02786 
02787 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
02788 struct rb_objspace *rb_objspace_alloc(void);
02789 #endif
02790 
02791 void
02792 Init_BareVM(void)
02793 {
02794     /* VM bootstrap: phase 1 */
02795     rb_vm_t * vm = ruby_mimmalloc(sizeof(*vm));
02796     rb_thread_t * th = ruby_mimmalloc(sizeof(*th));
02797     if (!vm || !th) {
02798         fprintf(stderr, "[FATAL] failed to allocate memory\n");
02799         exit(EXIT_FAILURE);
02800     }
02801     MEMZERO(th, rb_thread_t, 1);
02802     rb_thread_set_current_raw(th);
02803 
02804     vm_init2(vm);
02805 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
02806     vm->objspace = rb_objspace_alloc();
02807 #endif
02808     ruby_current_vm = vm;
02809 
02810     Init_native_thread();
02811     th->vm = vm;
02812     th_init(th, 0);
02813     ruby_thread_init_stack(th);
02814     vm->defined_module_hash = rb_hash_new();
02815 }
02816 
02817 /* top self */
02818 
02819 static VALUE
02820 main_to_s(VALUE obj)
02821 {
02822     return rb_str_new2("main");
02823 }
02824 
02825 VALUE
02826 rb_vm_top_self(void)
02827 {
02828     return GET_VM()->top_self;
02829 }
02830 
02831 void
02832 Init_top_self(void)
02833 {
02834     rb_vm_t *vm = GET_VM();
02835 
02836     vm->top_self = rb_obj_alloc(rb_cObject);
02837     rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
02838     rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");
02839 
02840     /* initialize mark object array, hash */
02841     vm->mark_object_ary = rb_ary_tmp_new(1);
02842 }
02843 
02844 VALUE *
02845 ruby_vm_verbose_ptr(rb_vm_t *vm)
02846 {
02847     return &vm->verbose;
02848 }
02849 
02850 VALUE *
02851 ruby_vm_debug_ptr(rb_vm_t *vm)
02852 {
02853     return &vm->debug;
02854 }
02855 
02856 VALUE *
02857 rb_ruby_verbose_ptr(void)
02858 {
02859     return ruby_vm_verbose_ptr(GET_VM());
02860 }
02861 
02862 VALUE *
02863 rb_ruby_debug_ptr(void)
02864 {
02865     return ruby_vm_debug_ptr(GET_VM());
02866 }
02867 
02868 /* iseq.c */
02869 VALUE rb_insn_operand_intern(rb_iseq_t *iseq,
02870                              VALUE insn, int op_no, VALUE op,
02871                              int len, size_t pos, VALUE *pnop, VALUE child);
02872 
02873 #if VM_COLLECT_USAGE_DETAILS
02874 
02875 #define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
02876 
02877 /* uh = {
02878  *   insn(Fixnum) => ihash(Hash)
02879  * }
02880  * ihash = {
02881  *   -1(Fixnum) => count,      # insn usage
02882  *    0(Fixnum) => ophash,     # operand usage
02883  * }
02884  * ophash = {
02885  *   val(interned string) => count(Fixnum)
02886  * }
02887  */
02888 static void
02889 vm_analysis_insn(int insn)
02890 {
02891     ID usage_hash;
02892     ID bigram_hash;
02893     static int prev_insn = -1;
02894 
02895     VALUE uh;
02896     VALUE ihash;
02897     VALUE cv;
02898 
02899     CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
02900     CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM");
02901     uh = rb_const_get(rb_cRubyVM, usage_hash);
02902     if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) {
02903         ihash = rb_hash_new();
02904         HASH_ASET(uh, INT2FIX(insn), ihash);
02905     }
02906     if ((cv = rb_hash_aref(ihash, INT2FIX(-1))) == Qnil) {
02907         cv = INT2FIX(0);
02908     }
02909     HASH_ASET(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1));
02910 
02911     /* calc bigram */
02912     if (prev_insn != -1) {
02913         VALUE bi;
02914         VALUE ary[2];
02915         VALUE cv;
02916 
02917         ary[0] = INT2FIX(prev_insn);
02918         ary[1] = INT2FIX(insn);
02919         bi = rb_ary_new4(2, &ary[0]);
02920 
02921         uh = rb_const_get(rb_cRubyVM, bigram_hash);
02922         if ((cv = rb_hash_aref(uh, bi)) == Qnil) {
02923             cv = INT2FIX(0);
02924         }
02925         HASH_ASET(uh, bi, INT2FIX(FIX2INT(cv) + 1));
02926     }
02927     prev_insn = insn;
02928 }
02929 
02930 static void
02931 vm_analysis_operand(int insn, int n, VALUE op)
02932 {
02933     ID usage_hash;
02934 
02935     VALUE uh;
02936     VALUE ihash;
02937     VALUE ophash;
02938     VALUE valstr;
02939     VALUE cv;
02940 
02941     CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
02942 
02943     uh = rb_const_get(rb_cRubyVM, usage_hash);
02944     if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) {
02945         ihash = rb_hash_new();
02946         HASH_ASET(uh, INT2FIX(insn), ihash);
02947     }
02948     if ((ophash = rb_hash_aref(ihash, INT2FIX(n))) == Qnil) {
02949         ophash = rb_hash_new();
02950         HASH_ASET(ihash, INT2FIX(n), ophash);
02951     }
02952     /* intern */
02953     valstr = rb_insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
02954 
02955     /* set count */
02956     if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) {
02957         cv = INT2FIX(0);
02958     }
02959     HASH_ASET(ophash, valstr, INT2FIX(FIX2INT(cv) + 1));
02960 }
02961 
02962 static void
02963 vm_analysis_register(int reg, int isset)
02964 {
02965     ID usage_hash;
02966     VALUE uh;
02967     VALUE valstr;
02968     static const char regstrs[][5] = {
02969         "pc",                   /* 0 */
02970         "sp",                   /* 1 */
02971         "ep",                   /* 2 */
02972         "cfp",                  /* 3 */
02973         "self",                 /* 4 */
02974         "iseq",                 /* 5 */
02975     };
02976     static const char getsetstr[][4] = {
02977         "get",
02978         "set",
02979     };
02980     static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2];
02981 
02982     VALUE cv;
02983 
02984     CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS");
02985     if (syms[0] == 0) {
02986         char buff[0x10];
02987         int i;
02988 
02989         for (i = 0; i < (int)(sizeof(regstrs) / sizeof(regstrs[0])); i++) {
02990             int j;
02991             for (j = 0; j < 2; j++) {
02992                 snprintf(buff, 0x10, "%d %s %-4s", i, getsetstr[j], regstrs[i]);
02993                 syms[i][j] = ID2SYM(rb_intern(buff));
02994             }
02995         }
02996     }
02997     valstr = syms[reg][isset];
02998 
02999     uh = rb_const_get(rb_cRubyVM, usage_hash);
03000     if ((cv = rb_hash_aref(uh, valstr)) == Qnil) {
03001         cv = INT2FIX(0);
03002     }
03003     HASH_ASET(uh, valstr, INT2FIX(FIX2INT(cv) + 1));
03004 }
03005 
03006 #undef HASH_ASET
03007 
03008 void (*ruby_vm_collect_usage_func_insn)(int insn) = vm_analysis_insn;
03009 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = vm_analysis_operand;
03010 void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = vm_analysis_register;
03011 
03012 /* :nodoc: */
03013 static VALUE
03014 usage_analysis_insn_stop(VALUE self)
03015 {
03016     ruby_vm_collect_usage_func_insn = 0;
03017     return Qnil;
03018 }
03019 
03020 /* :nodoc: */
03021 static VALUE
03022 usage_analysis_operand_stop(VALUE self)
03023 {
03024     ruby_vm_collect_usage_func_operand = 0;
03025     return Qnil;
03026 }
03027 
03028 /* :nodoc: */
03029 static VALUE
03030 usage_analysis_register_stop(VALUE self)
03031 {
03032     ruby_vm_collect_usage_func_register = 0;
03033     return Qnil;
03034 }
03035 
03036 #else
03037 
03038 void (*ruby_vm_collect_usage_func_insn)(int insn) = NULL;
03039 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = NULL;
03040 void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = NULL;
03041 
03042 #endif
03043 
03044 #if VM_COLLECT_USAGE_DETAILS
03045 /* @param insn instruction number */
03046 static void
03047 vm_collect_usage_insn(int insn)
03048 {
03049     if (RUBY_DTRACE_INSN_ENABLED()) {
03050         RUBY_DTRACE_INSN(rb_insns_name(insn));
03051     }
03052     if (ruby_vm_collect_usage_func_insn)
03053         (*ruby_vm_collect_usage_func_insn)(insn);
03054 }
03055 
03056 /* @param insn instruction number
03057  * @param n    n-th operand
03058  * @param op   operand value
03059  */
03060 static void
03061 vm_collect_usage_operand(int insn, int n, VALUE op)
03062 {
03063     if (RUBY_DTRACE_INSN_OPERAND_ENABLED()) {
03064         VALUE valstr;
03065 
03066         valstr = rb_insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
03067 
03068         RUBY_DTRACE_INSN_OPERAND(RSTRING_PTR(valstr), rb_insns_name(insn));
03069         RB_GC_GUARD(valstr);
03070     }
03071     if (ruby_vm_collect_usage_func_operand)
03072         (*ruby_vm_collect_usage_func_operand)(insn, n, op);
03073 }
03074 
03075 /* @param reg register id. see code of vm_analysis_register() */
03076 /* @param iseset 0: read, 1: write */
03077 static void
03078 vm_collect_usage_register(int reg, int isset)
03079 {
03080     if (ruby_vm_collect_usage_func_register)
03081         (*ruby_vm_collect_usage_func_register)(reg, isset);
03082 }
03083 #endif
03084 
03085 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7