vm.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   vm.c -
00004 
00005   $Author: yugui $
00006 
00007   Copyright (C) 2004-2007 Koichi Sasada
00008 
00009 **********************************************************************/
00010 
00011 #include "ruby/ruby.h"
00012 #include "ruby/st.h"
00013 #include "ruby/encoding.h"
00014 
00015 #include "gc.h"
00016 #include "vm_core.h"
00017 #include "iseq.h"
00018 #include "eval_intern.h"
00019 
00020 #include "vm_insnhelper.h"
00021 #include "vm_insnhelper.c"
00022 #include "vm_exec.h"
00023 #include "vm_exec.c"
00024 
00025 #include "vm_method.c"
00026 #include "vm_eval.c"
00027 
00028 #include <assert.h>
00029 
00030 #define BUFSIZE 0x100
00031 #define PROCDEBUG 0
00032 
00033 VALUE rb_cRubyVM;
00034 VALUE rb_cThread;
00035 VALUE rb_cEnv;
00036 VALUE rb_mRubyVMFrozenCore;
00037 
00038 VALUE ruby_vm_global_state_version = 1;
00039 VALUE ruby_vm_const_missing_count = 0;
00040 
00041 char ruby_vm_redefined_flag[BOP_LAST_];
00042 
00043 rb_thread_t *ruby_current_thread = 0;
00044 rb_vm_t *ruby_current_vm = 0;
00045 
00046 static void thread_free(void *ptr);
00047 
00048 VALUE rb_insns_name_array(void);
00049 
00050 void vm_analysis_operand(int insn, int n, VALUE op);
00051 void vm_analysis_register(int reg, int isset);
00052 void vm_analysis_insn(int insn);
00053 
00054 void
00055 rb_vm_change_state(void)
00056 {
00057     INC_VM_STATE_VERSION();
00058 }
00059 
00060 void
00061 rb_vm_inc_const_missing_count(void)
00062 {
00063     ruby_vm_const_missing_count +=1;
00064 }
00065 
00066 /* control stack frame */
00067 
00068 static inline VALUE
00069 rb_vm_set_finish_env(rb_thread_t * th)
00070 {
00071     vm_push_frame(th, 0, VM_FRAME_MAGIC_FINISH,
00072                   Qnil, th->cfp->lfp[0], 0,
00073                   th->cfp->sp, 0, 1);
00074     th->cfp->pc = (VALUE *)&finish_insn_seq[0];
00075     return Qtrue;
00076 }
00077 
00078 static void
00079 vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
00080 {
00081     rb_iseq_t *iseq;
00082     GetISeqPtr(iseqval, iseq);
00083 
00084     if (iseq->type != ISEQ_TYPE_TOP) {
00085         rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
00086     }
00087 
00088     /* for return */
00089     rb_vm_set_finish_env(th);
00090 
00091     vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
00092                   th->top_self, 0, iseq->iseq_encoded,
00093                   th->cfp->sp, 0, iseq->local_size);
00094 
00095     CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
00096 }
00097 
00098 static void
00099 vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref)
00100 {
00101     rb_iseq_t *iseq;
00102     rb_block_t * const block = th->base_block;
00103     GetISeqPtr(iseqval, iseq);
00104 
00105     /* for return */
00106     rb_vm_set_finish_env(th);
00107     vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
00108                   GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded,
00109                   th->cfp->sp, block->lfp, iseq->local_size);
00110 
00111     if (cref) {
00112         th->cfp->dfp[-1] = (VALUE)cref;
00113     }
00114 
00115     CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
00116 }
00117 
00118 static void
00119 vm_set_main_stack(rb_thread_t *th, VALUE iseqval)
00120 {
00121     VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
00122     rb_binding_t *bind;
00123     rb_iseq_t *iseq;
00124     rb_env_t *env;
00125 
00126     GetBindingPtr(toplevel_binding, bind);
00127     GetEnvPtr(bind->env, env);
00128     th->base_block = &env->block;
00129     vm_set_eval_stack(th, iseqval, 0);
00130     th->base_block = 0;
00131 
00132     /* save binding */
00133     GetISeqPtr(iseqval, iseq);
00134     if (bind && iseq->local_size > 0) {
00135         bind->env = rb_vm_make_env_object(th, th->cfp);
00136     }
00137 
00138     CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
00139 }
00140 
00141 rb_control_frame_t *
00142 rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
00143 {
00144     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00145         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00146             return cfp;
00147         }
00148         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00149     }
00150     return 0;
00151 }
00152 
00153 static rb_control_frame_t *
00154 vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
00155 {
00156     if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00157         return cfp;
00158     }
00159 
00160     cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00161 
00162     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00163         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00164             return cfp;
00165         }
00166 
00167         if ((cfp->flag & VM_FRAME_FLAG_PASSED) == 0) {
00168             break;
00169         }
00170         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00171     }
00172     return 0;
00173 }
00174 
00175 /* Env */
00176 
00177 /*
00178   env{
00179     env[0] // special (block or prev env)
00180     env[1] // env object
00181     env[2] // prev env val
00182   };
00183  */
00184 
00185 #define ENV_IN_HEAP_P(th, env)  \
00186   (!((th)->stack < (env) && (env) < ((th)->stack + (th)->stack_size)))
00187 #define ENV_VAL(env)        ((env)[1])
00188 
00189 static void
00190 env_mark(void * const ptr)
00191 {
00192     RUBY_MARK_ENTER("env");
00193     if (ptr) {
00194         const rb_env_t * const env = ptr;
00195 
00196         if (env->env) {
00197             /* TODO: should mark more restricted range */
00198             RUBY_GC_INFO("env->env\n");
00199             rb_gc_mark_locations(env->env, env->env + env->env_size);
00200         }
00201 
00202         RUBY_GC_INFO("env->prev_envval\n");
00203         RUBY_MARK_UNLESS_NULL(env->prev_envval);
00204         RUBY_MARK_UNLESS_NULL(env->block.self);
00205         RUBY_MARK_UNLESS_NULL(env->block.proc);
00206 
00207         if (env->block.iseq) {
00208             if (BUILTIN_TYPE(env->block.iseq) == T_NODE) {
00209                 RUBY_MARK_UNLESS_NULL((VALUE)env->block.iseq);
00210             }
00211             else {
00212                 RUBY_MARK_UNLESS_NULL(env->block.iseq->self);
00213             }
00214         }
00215     }
00216     RUBY_MARK_LEAVE("env");
00217 }
00218 
00219 static void
00220 env_free(void * const ptr)
00221 {
00222     RUBY_FREE_ENTER("env");
00223     if (ptr) {
00224         const rb_env_t * const env = ptr;
00225         RUBY_FREE_UNLESS_NULL(env->env);
00226         ruby_xfree(ptr);
00227     }
00228     RUBY_FREE_LEAVE("env");
00229 }
00230 
00231 static size_t
00232 env_memsize(const void *ptr)
00233 {
00234     if (ptr) {
00235         const rb_env_t * const env = ptr;
00236         size_t size = sizeof(rb_env_t);
00237         if (env->env) {
00238             size += env->env_size * sizeof(VALUE);
00239         }
00240         return size;
00241     }
00242     return 0;
00243 }
00244 
00245 static const rb_data_type_t env_data_type = {
00246     "VM/env",
00247     env_mark, env_free, env_memsize,
00248 };
00249 
00250 static VALUE
00251 env_alloc(void)
00252 {
00253     VALUE obj;
00254     rb_env_t *env;
00255     obj = TypedData_Make_Struct(rb_cEnv, rb_env_t, &env_data_type, env);
00256     env->env = 0;
00257     env->prev_envval = 0;
00258     env->block.iseq = 0;
00259     return obj;
00260 }
00261 
00262 static VALUE check_env_value(VALUE envval);
00263 
00264 static int
00265 check_env(rb_env_t * const env)
00266 {
00267     printf("---\n");
00268     printf("envptr: %p\n", (void *)&env->block.dfp[0]);
00269     printf("orphan: %p\n", (void *)env->block.dfp[1]);
00270     printf("inheap: %p\n", (void *)env->block.dfp[2]);
00271     printf("envval: %10p ", (void *)env->block.dfp[3]);
00272     dp(env->block.dfp[3]);
00273     printf("penvv : %10p ", (void *)env->block.dfp[4]);
00274     dp(env->block.dfp[4]);
00275     printf("lfp:    %10p\n", (void *)env->block.lfp);
00276     printf("dfp:    %10p\n", (void *)env->block.dfp);
00277     if (env->block.dfp[4]) {
00278         printf(">>\n");
00279         check_env_value(env->block.dfp[4]);
00280         printf("<<\n");
00281     }
00282     return 1;
00283 }
00284 
00285 static VALUE
00286 check_env_value(VALUE envval)
00287 {
00288     rb_env_t *env;
00289     GetEnvPtr(envval, env);
00290 
00291     if (check_env(env)) {
00292         return envval;
00293     }
00294     rb_bug("invalid env");
00295     return Qnil;                /* unreachable */
00296 }
00297 
00298 static VALUE
00299 vm_make_env_each(rb_thread_t * const th, rb_control_frame_t * const cfp,
00300                  VALUE *envptr, VALUE * const endptr)
00301 {
00302     VALUE envval, penvval = 0;
00303     rb_env_t *env;
00304     VALUE *nenvptr;
00305     int i, local_size;
00306 
00307     if (ENV_IN_HEAP_P(th, envptr)) {
00308         return ENV_VAL(envptr);
00309     }
00310 
00311     if (envptr != endptr) {
00312         VALUE *penvptr = GC_GUARDED_PTR_REF(*envptr);
00313         rb_control_frame_t *pcfp = cfp;
00314 
00315         if (ENV_IN_HEAP_P(th, penvptr)) {
00316             penvval = ENV_VAL(penvptr);
00317         }
00318         else {
00319             while (pcfp->dfp != penvptr) {
00320                 pcfp++;
00321                 if (pcfp->dfp == 0) {
00322                     SDR();
00323                     rb_bug("invalid dfp");
00324                 }
00325             }
00326             penvval = vm_make_env_each(th, pcfp, penvptr, endptr);
00327             cfp->lfp = pcfp->lfp;
00328             *envptr = GC_GUARDED_PTR(pcfp->dfp);
00329         }
00330     }
00331 
00332     /* allocate env */
00333     envval = env_alloc();
00334     GetEnvPtr(envval, env);
00335 
00336     if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00337         local_size = 2;
00338     }
00339     else {
00340         local_size = cfp->iseq->local_size;
00341     }
00342 
00343     env->env_size = local_size + 1 + 2;
00344     env->local_size = local_size;
00345     env->env = ALLOC_N(VALUE, env->env_size);
00346     env->prev_envval = penvval;
00347 
00348     for (i = 0; i <= local_size; i++) {
00349         env->env[i] = envptr[-local_size + i];
00350 #if 0
00351         fprintf(stderr, "%2d ", &envptr[-local_size + i] - th->stack); dp(env->env[i]);
00352         if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00353             /* clear value stack for GC */
00354             envptr[-local_size + i] = 0;
00355         }
00356 #endif
00357     }
00358 
00359     *envptr = envval;           /* GC mark */
00360     nenvptr = &env->env[i - 1];
00361     nenvptr[1] = envval;        /* frame self */
00362     nenvptr[2] = penvval;       /* frame prev env object */
00363 
00364     /* reset lfp/dfp in cfp */
00365     cfp->dfp = nenvptr;
00366     if (envptr == endptr) {
00367         cfp->lfp = nenvptr;
00368     }
00369 
00370     /* as Binding */
00371     env->block.self = cfp->self;
00372     env->block.lfp = cfp->lfp;
00373     env->block.dfp = cfp->dfp;
00374     env->block.iseq = cfp->iseq;
00375 
00376     if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
00377         /* TODO */
00378         env->block.iseq = 0;
00379     }
00380     return envval;
00381 }
00382 
00383 static int
00384 collect_local_variables_in_iseq(rb_iseq_t *iseq, const VALUE ary)
00385 {
00386     int i;
00387     if (!iseq) return 0;
00388     for (i = 0; i < iseq->local_table_size; i++) {
00389         ID lid = iseq->local_table[i];
00390         if (rb_is_local_id(lid)) {
00391             rb_ary_push(ary, ID2SYM(lid));
00392         }
00393     }
00394     return 1;
00395 }
00396 
00397 static int
00398 collect_local_variables_in_env(rb_env_t * env, const VALUE ary)
00399 {
00400 
00401     while (collect_local_variables_in_iseq(env->block.iseq, ary),
00402            env->prev_envval) {
00403         GetEnvPtr(env->prev_envval, env);
00404     }
00405     return 0;
00406 }
00407 
00408 static int
00409 vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary)
00410 {
00411     if (ENV_IN_HEAP_P(th, dfp)) {
00412         rb_env_t *env;
00413         GetEnvPtr(ENV_VAL(dfp), env);
00414         collect_local_variables_in_env(env, ary);
00415         return 1;
00416     }
00417     else {
00418         return 0;
00419     }
00420 }
00421 
00422 VALUE
00423 rb_vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp)
00424 {
00425     VALUE envval;
00426 
00427     if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) {
00428         /* for method_missing */
00429         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00430     }
00431 
00432     envval = vm_make_env_each(th, cfp, cfp->dfp, cfp->lfp);
00433 
00434     if (PROCDEBUG) {
00435         check_env_value(envval);
00436     }
00437 
00438     return envval;
00439 }
00440 
00441 void
00442 rb_vm_stack_to_heap(rb_thread_t * const th)
00443 {
00444     rb_control_frame_t *cfp = th->cfp;
00445     while ((cfp = rb_vm_get_ruby_level_next_cfp(th, cfp)) != 0) {
00446         rb_vm_make_env_object(th, cfp);
00447         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00448     }
00449 }
00450 
00451 /* Proc */
00452 
00453 static VALUE
00454 vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block)
00455 {
00456     VALUE proc = block->proc;
00457 
00458     if (block->proc) {
00459         return block->proc;
00460     }
00461 
00462     proc = rb_vm_make_proc(th, block, rb_cProc);
00463     block->proc = proc;
00464 
00465     return proc;
00466 }
00467 
00468 VALUE
00469 rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
00470 {
00471     VALUE procval, envval, blockprocval = 0;
00472     rb_proc_t *proc;
00473     rb_control_frame_t *cfp = RUBY_VM_GET_CFP_FROM_BLOCK_PTR(block);
00474 
00475     if (block->proc) {
00476         rb_bug("rb_vm_make_proc: Proc value is already created.");
00477     }
00478 
00479     if (GC_GUARDED_PTR_REF(cfp->lfp[0])) {
00480             rb_proc_t *p;
00481 
00482             blockprocval = vm_make_proc_from_block(
00483                 th, (rb_block_t *)GC_GUARDED_PTR_REF(*cfp->lfp));
00484 
00485             GetProcPtr(blockprocval, p);
00486             *cfp->lfp = GC_GUARDED_PTR(&p->block);
00487         }
00488 
00489     envval = rb_vm_make_env_object(th, cfp);
00490 
00491     if (PROCDEBUG) {
00492         check_env_value(envval);
00493     }
00494     procval = rb_proc_alloc(klass);
00495     GetProcPtr(procval, proc);
00496     proc->blockprocval = blockprocval;
00497     proc->block.self = block->self;
00498     proc->block.lfp = block->lfp;
00499     proc->block.dfp = block->dfp;
00500     proc->block.iseq = block->iseq;
00501     proc->block.proc = procval;
00502     proc->envval = envval;
00503     proc->safe_level = th->safe_level;
00504 
00505     if (VMDEBUG) {
00506         if (th->stack < block->dfp && block->dfp < th->stack + th->stack_size) {
00507             rb_bug("invalid ptr: block->dfp");
00508         }
00509         if (th->stack < block->lfp && block->lfp < th->stack + th->stack_size) {
00510             rb_bug("invalid ptr: block->lfp");
00511         }
00512     }
00513 
00514     return procval;
00515 }
00516 
00517 /* C -> Ruby: block */
00518 
00519 static inline VALUE
00520 invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
00521                     VALUE self, int argc, const VALUE *argv,
00522                     const rb_block_t *blockptr, const NODE *cref)
00523 {
00524     if (SPECIAL_CONST_P(block->iseq))
00525         return Qnil;
00526     else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
00527         const rb_iseq_t *iseq = block->iseq;
00528         const rb_control_frame_t *cfp;
00529         rb_control_frame_t *ncfp;
00530         int i, opt_pc, arg_size = iseq->arg_size;
00531         int type = block_proc_is_lambda(block->proc) ?
00532           VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
00533 
00534         rb_vm_set_finish_env(th);
00535 
00536         cfp = th->cfp;
00537         CHECK_STACK_OVERFLOW(cfp, argc + iseq->stack_max);
00538 
00539         for (i=0; i<argc; i++) {
00540             cfp->sp[i] = argv[i];
00541         }
00542 
00543         opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
00544                                      type == VM_FRAME_MAGIC_LAMBDA);
00545 
00546         ncfp = vm_push_frame(th, iseq, type,
00547                              self, GC_GUARDED_PTR(block->dfp),
00548                              iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
00549                              iseq->local_size - arg_size);
00550         ncfp->me = th->passed_me;
00551         th->passed_me = 0;
00552         th->passed_block = blockptr;
00553 
00554         if (cref) {
00555             th->cfp->dfp[-1] = (VALUE)cref;
00556         }
00557 
00558         return vm_exec(th);
00559     }
00560     else {
00561         return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
00562     }
00563 }
00564 
00565 static inline const rb_block_t *
00566 check_block(rb_thread_t *th)
00567 {
00568     const rb_block_t *blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
00569 
00570     if (blockptr == 0) {
00571         rb_vm_localjump_error("no block given", Qnil, 0);
00572     }
00573 
00574     return blockptr;
00575 }
00576 
00577 static inline VALUE
00578 vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref)
00579 {
00580     const rb_block_t *blockptr = check_block(th);
00581     return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref);
00582 }
00583 
00584 static inline VALUE
00585 vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
00586 {
00587     const rb_block_t *blockptr = check_block(th);
00588     return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0);
00589 }
00590 
00591 VALUE
00592 rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
00593                   int argc, const VALUE *argv, const rb_block_t * blockptr)
00594 {
00595     VALUE val = Qundef;
00596     int state;
00597     volatile int stored_safe = th->safe_level;
00598 
00599     TH_PUSH_TAG(th);
00600     if ((state = EXEC_TAG()) == 0) {
00601         if (!proc->is_from_method) {
00602             th->safe_level = proc->safe_level;
00603         }
00604         val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0);
00605     }
00606     TH_POP_TAG();
00607 
00608     if (!proc->is_from_method) {
00609         th->safe_level = stored_safe;
00610     }
00611 
00612     if (state) {
00613         JUMP_TAG(state);
00614     }
00615     return val;
00616 }
00617 
00618 /* special variable */
00619 
00620 static rb_control_frame_t *
00621 vm_normal_frame(rb_thread_t *th, rb_control_frame_t *cfp)
00622 {
00623     while (cfp->pc == 0) {
00624         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
00625         if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
00626             return 0;
00627         }
00628     }
00629     return cfp;
00630 }
00631 
00632 static VALUE
00633 vm_cfp_svar_get(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key)
00634 {
00635     cfp = vm_normal_frame(th, cfp);
00636     return lfp_svar_get(th, cfp ? cfp->lfp : 0, key);
00637 }
00638 
00639 static void
00640 vm_cfp_svar_set(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key, const VALUE val)
00641 {
00642     cfp = vm_normal_frame(th, cfp);
00643     lfp_svar_set(th, cfp ? cfp->lfp : 0, key, val);
00644 }
00645 
00646 static VALUE
00647 vm_svar_get(VALUE key)
00648 {
00649     rb_thread_t *th = GET_THREAD();
00650     return vm_cfp_svar_get(th, th->cfp, key);
00651 }
00652 
00653 static void
00654 vm_svar_set(VALUE key, VALUE val)
00655 {
00656     rb_thread_t *th = GET_THREAD();
00657     vm_cfp_svar_set(th, th->cfp, key, val);
00658 }
00659 
00660 VALUE
00661 rb_backref_get(void)
00662 {
00663     return vm_svar_get(1);
00664 }
00665 
00666 void
00667 rb_backref_set(VALUE val)
00668 {
00669     vm_svar_set(1, val);
00670 }
00671 
00672 VALUE
00673 rb_lastline_get(void)
00674 {
00675     return vm_svar_get(0);
00676 }
00677 
00678 void
00679 rb_lastline_set(VALUE val)
00680 {
00681     vm_svar_set(0, val);
00682 }
00683 
00684 /* backtrace */
00685 
00686 int
00687 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
00688 {
00689     int line_no = 0;
00690     const rb_iseq_t *iseq = cfp->iseq;
00691 
00692     if (RUBY_VM_NORMAL_ISEQ_P(iseq) && iseq->insn_info_size > 0) {
00693         rb_num_t i;
00694         size_t pos = cfp->pc - cfp->iseq->iseq_encoded;
00695 
00696         if (iseq->insn_info_table[0].position == pos) goto found;
00697         for (i = 1; i < iseq->insn_info_size; i++) {
00698             if (iseq->insn_info_table[i].position == pos) {
00699                 line_no = iseq->insn_info_table[i - 1].line_no;
00700                 goto found;
00701             }
00702         }
00703         line_no = iseq->insn_info_table[i - 1].line_no;
00704     }
00705   found:
00706     return line_no;
00707 }
00708 
00709 static int
00710 vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg)
00711 {
00712     const rb_control_frame_t *limit_cfp = th->cfp;
00713     const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
00714     VALUE file = Qnil;
00715     int line_no = 0;
00716 
00717     cfp -= 2;
00718     while (lev-- >= 0) {
00719         if (++limit_cfp > cfp) {
00720             return FALSE;
00721         }
00722     }
00723     if (init) (*init)(arg);
00724     limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp);
00725     if (th->vm->progname) file = th->vm->progname;
00726     while (cfp > limit_cfp) {
00727         if (cfp->iseq != 0) {
00728             if (cfp->pc != 0) {
00729                 rb_iseq_t *iseq = cfp->iseq;
00730 
00731                 line_no = rb_vm_get_sourceline(cfp);
00732                 file = iseq->filename;
00733                 if ((*iter)(arg, file, line_no, iseq->name)) break;
00734             }
00735         }
00736         else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
00737             ID id;
00738             extern VALUE ruby_engine_name;
00739 
00740             if (NIL_P(file)) file = ruby_engine_name;
00741             if (cfp->me->def)
00742                 id = cfp->me->def->original_id;
00743             else
00744                 id = cfp->me->called_id;
00745             if (id != ID_ALLOCATOR && (*iter)(arg, file, line_no, rb_id2str(id)))
00746                 break;
00747         }
00748         cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
00749     }
00750     return TRUE;
00751 }
00752 
00753 static void
00754 vm_backtrace_alloc(void *arg)
00755 {
00756     VALUE *aryp = arg;
00757     *aryp = rb_ary_new();
00758 }
00759 
00760 static int
00761 vm_backtrace_push(void *arg, VALUE file, int line_no, VALUE name)
00762 {
00763     VALUE *aryp = arg;
00764     VALUE bt;
00765 
00766     if (line_no) {
00767         bt = rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
00768                             RSTRING_PTR(file), line_no, RSTRING_PTR(name));
00769     }
00770     else {
00771         bt = rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
00772                             RSTRING_PTR(file), RSTRING_PTR(name));
00773     }
00774     rb_ary_push(*aryp, bt);
00775     return 0;
00776 }
00777 
00778 static inline VALUE
00779 vm_backtrace(rb_thread_t *th, int lev)
00780 {
00781     VALUE ary = 0;
00782 
00783     if (lev < 0) {
00784         ary = rb_ary_new();
00785     }
00786     vm_backtrace_each(th, lev, vm_backtrace_alloc, vm_backtrace_push, &ary);
00787     if (!ary) return Qnil;
00788     return rb_ary_reverse(ary);
00789 }
00790 
00791 const char *
00792 rb_sourcefile(void)
00793 {
00794     rb_thread_t *th = GET_THREAD();
00795     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00796 
00797     if (cfp) {
00798         return RSTRING_PTR(cfp->iseq->filename);
00799     }
00800     else {
00801         return 0;
00802     }
00803 }
00804 
00805 int
00806 rb_sourceline(void)
00807 {
00808     rb_thread_t *th = GET_THREAD();
00809     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00810 
00811     if (cfp) {
00812         return rb_vm_get_sourceline(cfp);
00813     }
00814     else {
00815         return 0;
00816     }
00817 }
00818 
00819 NODE *
00820 rb_vm_cref(void)
00821 {
00822     rb_thread_t *th = GET_THREAD();
00823     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00824     return vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
00825 }
00826 
00827 #if 0
00828 void
00829 debug_cref(NODE *cref)
00830 {
00831     while (cref) {
00832         dp(cref->nd_clss);
00833         printf("%ld\n", cref->nd_visi);
00834         cref = cref->nd_next;
00835     }
00836 }
00837 #endif
00838 
00839 VALUE
00840 rb_vm_cbase(void)
00841 {
00842     rb_thread_t *th = GET_THREAD();
00843     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00844 
00845     return vm_get_cbase(cfp->iseq, cfp->lfp, cfp->dfp);
00846 }
00847 
00848 /* jump */
00849 
00850 static VALUE
00851 make_localjump_error(const char *mesg, VALUE value, int reason)
00852 {
00853     extern VALUE rb_eLocalJumpError;
00854     VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
00855     ID id;
00856 
00857     switch (reason) {
00858       case TAG_BREAK:
00859         CONST_ID(id, "break");
00860         break;
00861       case TAG_REDO:
00862         CONST_ID(id, "redo");
00863         break;
00864       case TAG_RETRY:
00865         CONST_ID(id, "retry");
00866         break;
00867       case TAG_NEXT:
00868         CONST_ID(id, "next");
00869         break;
00870       case TAG_RETURN:
00871         CONST_ID(id, "return");
00872         break;
00873       default:
00874         CONST_ID(id, "noreason");
00875         break;
00876     }
00877     rb_iv_set(exc, "@exit_value", value);
00878     rb_iv_set(exc, "@reason", ID2SYM(id));
00879     return exc;
00880 }
00881 
00882 void
00883 rb_vm_localjump_error(const char *mesg, VALUE value, int reason)
00884 {
00885     VALUE exc = make_localjump_error(mesg, value, reason);
00886     rb_exc_raise(exc);
00887 }
00888 
00889 VALUE
00890 rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
00891 {
00892     VALUE result = Qnil;
00893 
00894     if (val == Qundef) {
00895         val = GET_THREAD()->tag->retval;
00896     }
00897     switch (state) {
00898       case 0:
00899         break;
00900       case TAG_RETURN:
00901         result = make_localjump_error("unexpected return", val, state);
00902         break;
00903       case TAG_BREAK:
00904         result = make_localjump_error("unexpected break", val, state);
00905         break;
00906       case TAG_NEXT:
00907         result = make_localjump_error("unexpected next", val, state);
00908         break;
00909       case TAG_REDO:
00910         result = make_localjump_error("unexpected redo", Qnil, state);
00911         break;
00912       case TAG_RETRY:
00913         result = make_localjump_error("retry outside of rescue clause", Qnil, state);
00914         break;
00915       default:
00916         break;
00917     }
00918     return result;
00919 }
00920 
00921 void
00922 rb_vm_jump_tag_but_local_jump(int state, VALUE val)
00923 {
00924     if (val != Qnil) {
00925         VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, val);
00926         rb_exc_raise(exc);
00927     }
00928     JUMP_TAG(state);
00929 }
00930 
00931 NORETURN(static void vm_iter_break(rb_thread_t *th));
00932 
00933 static void
00934 vm_iter_break(rb_thread_t *th)
00935 {
00936     rb_control_frame_t *cfp = th->cfp;
00937     VALUE *dfp = GC_GUARDED_PTR_REF(*cfp->dfp);
00938 
00939     th->state = TAG_BREAK;
00940     th->errinfo = (VALUE)NEW_THROW_OBJECT(Qnil, (VALUE)dfp, TAG_BREAK);
00941     TH_JUMP_TAG(th, TAG_BREAK);
00942 }
00943 
00944 void
00945 rb_iter_break(void)
00946 {
00947     vm_iter_break(GET_THREAD());
00948 }
00949 
00950 /* optimization: redefine management */
00951 
00952 static st_table *vm_opt_method_table = 0;
00953 
00954 static void
00955 rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me)
00956 {
00957     VALUE bop;
00958     if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) {
00959         if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
00960             ruby_vm_redefined_flag[bop] = 1;
00961         }
00962     }
00963 }
00964 
00965 static void
00966 add_opt_method(VALUE klass, ID mid, VALUE bop)
00967 {
00968     rb_method_entry_t *me;
00969     if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) && me->def &&
00970         me->def->type == VM_METHOD_TYPE_CFUNC) {
00971         st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
00972     }
00973     else {
00974         rb_bug("undefined optimized method: %s", rb_id2name(mid));
00975     }
00976 }
00977 
00978 static void
00979 vm_init_redefined_flag(void)
00980 {
00981     ID mid;
00982     VALUE bop;
00983 
00984     vm_opt_method_table = st_init_numtable();
00985 
00986 #define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)
00987 #define C(k) add_opt_method(rb_c##k, mid, bop)
00988     OP(PLUS, PLUS), (C(Fixnum), C(Float), C(String), C(Array));
00989     OP(MINUS, MINUS), (C(Fixnum));
00990     OP(MULT, MULT), (C(Fixnum), C(Float));
00991     OP(DIV, DIV), (C(Fixnum), C(Float));
00992     OP(MOD, MOD), (C(Fixnum), C(Float));
00993     OP(Eq, EQ), (C(Fixnum), C(Float), C(String));
00994     OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String));
00995     OP(LT, LT), (C(Fixnum));
00996     OP(LE, LE), (C(Fixnum));
00997     OP(LTLT, LTLT), (C(String), C(Array));
00998     OP(AREF, AREF), (C(Array), C(Hash));
00999     OP(ASET, ASET), (C(Array), C(Hash));
01000     OP(Length, LENGTH), (C(Array), C(String), C(Hash));
01001     OP(Size, SIZE), (C(Array), C(String), C(Hash));
01002     OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
01003     OP(GT, GT), (C(Fixnum));
01004     OP(GE, GE), (C(Fixnum));
01005 #undef C
01006 #undef OP
01007 }
01008 
01009 /* for vm development */
01010 
01011 #if VMDEBUG
01012 static const char *
01013 vm_frametype_name(const rb_control_frame_t *cfp)
01014 {
01015     switch (VM_FRAME_TYPE(cfp)) {
01016       case VM_FRAME_MAGIC_METHOD: return "method";
01017       case VM_FRAME_MAGIC_BLOCK:  return "block";
01018       case VM_FRAME_MAGIC_CLASS:  return "class";
01019       case VM_FRAME_MAGIC_TOP:    return "top";
01020       case VM_FRAME_MAGIC_FINISH: return "finish";
01021       case VM_FRAME_MAGIC_CFUNC:  return "cfunc";
01022       case VM_FRAME_MAGIC_PROC:   return "proc";
01023       case VM_FRAME_MAGIC_IFUNC:  return "ifunc";
01024       case VM_FRAME_MAGIC_EVAL:   return "eval";
01025       case VM_FRAME_MAGIC_LAMBDA: return "lambda";
01026       default:
01027         rb_bug("unknown frame");
01028     }
01029 }
01030 #endif
01031 
01032 /* evaluator body */
01033 
01034 /*                  finish
01035   VMe (h1)          finish
01036     VM              finish F1 F2
01037       cfunc         finish F1 F2 C1
01038         rb_funcall  finish F1 F2 C1
01039           VMe       finish F1 F2 C1
01040             VM      finish F1 F2 C1 F3
01041 
01042   F1 - F3 : pushed by VM
01043   C1      : pushed by send insn (CFUNC)
01044 
01045   struct CONTROL_FRAME {
01046     VALUE *pc;                  // cfp[0], program counter
01047     VALUE *sp;                  // cfp[1], stack pointer
01048     VALUE *bp;                  // cfp[2], base pointer
01049     rb_iseq_t *iseq;            // cfp[3], iseq
01050     VALUE flag;                 // cfp[4], magic
01051     VALUE self;                 // cfp[5], self
01052     VALUE *lfp;                 // cfp[6], local frame pointer
01053     VALUE *dfp;                 // cfp[7], dynamic frame pointer
01054     rb_iseq_t * block_iseq;     // cfp[8], block iseq
01055     VALUE proc;                 // cfp[9], always 0
01056   };
01057 
01058   struct BLOCK {
01059     VALUE self;
01060     VALUE *lfp;
01061     VALUE *dfp;
01062     rb_iseq_t *block_iseq;
01063     VALUE proc;
01064   };
01065 
01066   struct METHOD_CONTROL_FRAME {
01067     rb_control_frame_t frame;
01068   };
01069 
01070   struct METHOD_FRAME {
01071     VALUE arg0;
01072     ...
01073     VALUE argM;
01074     VALUE param0;
01075     ...
01076     VALUE paramN;
01077     VALUE cref;
01078     VALUE special;                         // lfp [1]
01079     struct block_object *block_ptr | 0x01; // lfp [0]
01080   };
01081 
01082   struct BLOCK_CONTROL_FRAME {
01083     rb_control_frame_t frame;
01084   };
01085 
01086   struct BLOCK_FRAME {
01087     VALUE arg0;
01088     ...
01089     VALUE argM;
01090     VALUE param0;
01091     ...
01092     VALUE paramN;
01093     VALUE cref;
01094     VALUE *(prev_ptr | 0x01); // DFP[0]
01095   };
01096 
01097   struct CLASS_CONTROL_FRAME {
01098     rb_control_frame_t frame;
01099   };
01100 
01101   struct CLASS_FRAME {
01102     VALUE param0;
01103     ...
01104     VALUE paramN;
01105     VALUE cref;
01106     VALUE prev_dfp; // for frame jump
01107   };
01108 
01109   struct C_METHOD_CONTROL_FRAME {
01110     VALUE *pc;                       // 0
01111     VALUE *sp;                       // stack pointer
01112     VALUE *bp;                       // base pointer (used in exception)
01113     rb_iseq_t *iseq;               // cmi
01114     VALUE magic;                     // C_METHOD_FRAME
01115     VALUE self;                      // ?
01116     VALUE *lfp;                      // lfp
01117     VALUE *dfp;                      // == lfp
01118     rb_iseq_t * block_iseq;        //
01119     VALUE proc;                      // always 0
01120   };
01121 
01122   struct C_BLOCK_CONTROL_FRAME {
01123     VALUE *pc;                       // point only "finish" insn
01124     VALUE *sp;                       // sp
01125     rb_iseq_t *iseq;               // ?
01126     VALUE magic;                     // C_METHOD_FRAME
01127     VALUE self;                      // needed?
01128     VALUE *lfp;                      // lfp
01129     VALUE *dfp;                      // lfp
01130     rb_iseq_t * block_iseq; // 0
01131   };
01132  */
01133 
01134 
01135 static VALUE
01136 vm_exec(rb_thread_t *th)
01137 {
01138     int state;
01139     VALUE result, err;
01140     VALUE initial = 0;
01141     VALUE *escape_dfp = NULL;
01142 
01143     TH_PUSH_TAG(th);
01144     _tag.retval = Qnil;
01145     if ((state = EXEC_TAG()) == 0) {
01146       vm_loop_start:
01147         result = vm_exec_core(th, initial);
01148         if ((state = th->state) != 0) {
01149             err = result;
01150             th->state = 0;
01151             goto exception_handler;
01152         }
01153     }
01154     else {
01155         int i;
01156         struct iseq_catch_table_entry *entry;
01157         unsigned long epc, cont_pc, cont_sp;
01158         VALUE catch_iseqval;
01159         rb_control_frame_t *cfp;
01160         VALUE type;
01161 
01162         err = th->errinfo;
01163 
01164       exception_handler:
01165         cont_pc = cont_sp = catch_iseqval = 0;
01166 
01167         while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
01168             if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
01169                 const rb_method_entry_t *me = th->cfp->me;
01170                 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass);
01171             }
01172             th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
01173         }
01174 
01175         cfp = th->cfp;
01176         epc = cfp->pc - cfp->iseq->iseq_encoded;
01177 
01178         if (state == TAG_BREAK || state == TAG_RETURN) {
01179             escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
01180 
01181             if (cfp->dfp == escape_dfp) {
01182                 if (state == TAG_RETURN) {
01183                     if ((cfp + 1)->pc != &finish_insn_seq[0]) {
01184                         SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->dfp);
01185                         SET_THROWOBJ_STATE(err, state = TAG_BREAK);
01186                     }
01187                     else {
01188                         for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01189                             entry = &cfp->iseq->catch_table[i];
01190                             if (entry->start < epc && entry->end >= epc) {
01191                                 if (entry->type == CATCH_TYPE_ENSURE) {
01192                                     catch_iseqval = entry->iseq;
01193                                     cont_pc = entry->cont;
01194                                     cont_sp = entry->sp;
01195                                     break;
01196                                 }
01197                             }
01198                         }
01199                         if (!catch_iseqval) {
01200                             result = GET_THROWOBJ_VAL(err);
01201                             th->errinfo = Qnil;
01202                             th->cfp += 2;
01203                             goto finish_vme;
01204                         }
01205                     }
01206                     /* through */
01207                 }
01208                 else {
01209                     /* TAG_BREAK */
01210 #if OPT_STACK_CACHING
01211                     initial = (GET_THROWOBJ_VAL(err));
01212 #else
01213                     *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
01214 #endif
01215                     th->errinfo = Qnil;
01216                     goto vm_loop_start;
01217                 }
01218             }
01219         }
01220 
01221         if (state == TAG_RAISE) {
01222             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01223                 entry = &cfp->iseq->catch_table[i];
01224                 if (entry->start < epc && entry->end >= epc) {
01225 
01226                     if (entry->type == CATCH_TYPE_RESCUE ||
01227                         entry->type == CATCH_TYPE_ENSURE) {
01228                         catch_iseqval = entry->iseq;
01229                         cont_pc = entry->cont;
01230                         cont_sp = entry->sp;
01231                         break;
01232                     }
01233                 }
01234             }
01235         }
01236         else if (state == TAG_RETRY) {
01237             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01238                 entry = &cfp->iseq->catch_table[i];
01239                 if (entry->start < epc && entry->end >= epc) {
01240 
01241                     if (entry->type == CATCH_TYPE_ENSURE) {
01242                         catch_iseqval = entry->iseq;
01243                         cont_pc = entry->cont;
01244                         cont_sp = entry->sp;
01245                         break;
01246                     }
01247                     else if (entry->type == CATCH_TYPE_RETRY) {
01248                         VALUE *escape_dfp;
01249                         escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
01250                         if (cfp->dfp == escape_dfp) {
01251                             cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
01252                             th->errinfo = Qnil;
01253                             goto vm_loop_start;
01254                         }
01255                     }
01256                 }
01257             }
01258         }
01259         else if (state == TAG_BREAK && ((VALUE)escape_dfp & ~0x03) == 0) {
01260             type = CATCH_TYPE_BREAK;
01261 
01262           search_restart_point:
01263             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01264                 entry = &cfp->iseq->catch_table[i];
01265 
01266                 if (entry->start < epc && entry->end >= epc) {
01267                     if (entry->type == CATCH_TYPE_ENSURE) {
01268                         catch_iseqval = entry->iseq;
01269                         cont_pc = entry->cont;
01270                         cont_sp = entry->sp;
01271                         break;
01272                     }
01273                     else if (entry->type == type) {
01274                         cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
01275                         cfp->sp = cfp->bp + entry->sp;
01276 
01277                         if (state != TAG_REDO) {
01278 #if OPT_STACK_CACHING
01279                             initial = (GET_THROWOBJ_VAL(err));
01280 #else
01281                             *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
01282 #endif
01283                         }
01284                         th->errinfo = Qnil;
01285                         goto vm_loop_start;
01286                     }
01287                 }
01288             }
01289         }
01290         else if (state == TAG_REDO) {
01291             type = CATCH_TYPE_REDO;
01292             goto search_restart_point;
01293         }
01294         else if (state == TAG_NEXT) {
01295             type = CATCH_TYPE_NEXT;
01296             goto search_restart_point;
01297         }
01298         else {
01299             for (i = 0; i < cfp->iseq->catch_table_size; i++) {
01300                 entry = &cfp->iseq->catch_table[i];
01301                 if (entry->start < epc && entry->end >= epc) {
01302 
01303                     if (entry->type == CATCH_TYPE_ENSURE) {
01304                         catch_iseqval = entry->iseq;
01305                         cont_pc = entry->cont;
01306                         cont_sp = entry->sp;
01307                         break;
01308                     }
01309                 }
01310             }
01311         }
01312 
01313         if (catch_iseqval != 0) {
01314             /* found catch table */
01315             rb_iseq_t *catch_iseq;
01316 
01317             /* enter catch scope */
01318             GetISeqPtr(catch_iseqval, catch_iseq);
01319             cfp->sp = cfp->bp + cont_sp;
01320             cfp->pc = cfp->iseq->iseq_encoded + cont_pc;
01321 
01322             /* push block frame */
01323             cfp->sp[0] = err;
01324             vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
01325                           cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
01326                           cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1);
01327 
01328             state = 0;
01329             th->state = 0;
01330             th->errinfo = Qnil;
01331             goto vm_loop_start;
01332         }
01333         else {
01334             /* skip frame */
01335 
01336             switch (VM_FRAME_TYPE(th->cfp)) {
01337               case VM_FRAME_MAGIC_METHOD:
01338                 EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0);
01339                 break;
01340               case VM_FRAME_MAGIC_CLASS:
01341                 EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0);
01342                 break;
01343             }
01344 
01345             th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
01346 
01347             if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) {
01348                 goto exception_handler;
01349             }
01350             else {
01351                 vm_pop_frame(th);
01352                 th->errinfo = err;
01353                 TH_POP_TAG2();
01354                 JUMP_TAG(state);
01355             }
01356         }
01357     }
01358   finish_vme:
01359     TH_POP_TAG();
01360     return result;
01361 }
01362 
01363 /* misc */
01364 
01365 VALUE
01366 rb_iseq_eval(VALUE iseqval)
01367 {
01368     rb_thread_t *th = GET_THREAD();
01369     VALUE val;
01370     volatile VALUE tmp;
01371 
01372     vm_set_top_stack(th, iseqval);
01373 
01374     val = vm_exec(th);
01375     tmp = iseqval; /* prohibit tail call optimization */
01376     return val;
01377 }
01378 
01379 VALUE
01380 rb_iseq_eval_main(VALUE iseqval)
01381 {
01382     rb_thread_t *th = GET_THREAD();
01383     VALUE val;
01384     volatile VALUE tmp;
01385 
01386     vm_set_main_stack(th, iseqval);
01387 
01388     val = vm_exec(th);
01389     tmp = iseqval; /* prohibit tail call optimization */
01390     return val;
01391 }
01392 
01393 int
01394 rb_thread_method_id_and_class(rb_thread_t *th,
01395                               ID *idp, VALUE *klassp)
01396 {
01397     rb_control_frame_t *cfp = th->cfp;
01398     rb_iseq_t *iseq = cfp->iseq;
01399     if (!iseq && cfp->me) {
01400         if (idp) *idp = cfp->me->def->original_id;
01401         if (klassp) *klassp = cfp->me->klass;
01402         return 1;
01403     }
01404     while (iseq) {
01405         if (RUBY_VM_IFUNC_P(iseq)) {
01406             if (idp) CONST_ID(*idp, "<ifunc>");
01407             if (klassp) *klassp = 0;
01408             return 1;
01409         }
01410         if (iseq->defined_method_id) {
01411             if (idp) *idp = iseq->defined_method_id;
01412             if (klassp) *klassp = iseq->klass;
01413             return 1;
01414         }
01415         if (iseq->local_iseq == iseq) {
01416             break;
01417         }
01418         iseq = iseq->parent_iseq;
01419     }
01420     return 0;
01421 }
01422 
01423 int
01424 rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
01425 {
01426     return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp);
01427 }
01428 
01429 VALUE
01430 rb_thread_current_status(const rb_thread_t *th)
01431 {
01432     const rb_control_frame_t *cfp = th->cfp;
01433     VALUE str = Qnil;
01434 
01435     if (cfp->iseq != 0) {
01436         if (cfp->pc != 0) {
01437             rb_iseq_t *iseq = cfp->iseq;
01438             int line_no = rb_vm_get_sourceline(cfp);
01439             char *file = RSTRING_PTR(iseq->filename);
01440             str = rb_sprintf("%s:%d:in `%s'",
01441                              file, line_no, RSTRING_PTR(iseq->name));
01442         }
01443     }
01444     else if (cfp->me->def->original_id) {
01445         str = rb_sprintf("`%s#%s' (cfunc)",
01446                          RSTRING_PTR(rb_class_name(cfp->me->klass)),
01447                          rb_id2name(cfp->me->def->original_id));
01448     }
01449 
01450     return str;
01451 }
01452 
01453 VALUE
01454 rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
01455                  const rb_block_t *blockptr, VALUE filename, VALUE filepath)
01456 {
01457     rb_thread_t *th = GET_THREAD();
01458     const rb_control_frame_t *reg_cfp = th->cfp;
01459     volatile VALUE iseqval = rb_iseq_new(0, filename, filename, filepath, 0, ISEQ_TYPE_TOP);
01460     VALUE val;
01461 
01462     vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP,
01463                   recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
01464 
01465     val = (*func)(arg);
01466 
01467     vm_pop_frame(th);
01468     return val;
01469 }
01470 
01471 /* vm */
01472 
01473 static int
01474 vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy)
01475 {
01476     VALUE thval = (VALUE)key;
01477     rb_gc_mark(thval);
01478     return ST_CONTINUE;
01479 }
01480 
01481 static void
01482 mark_event_hooks(rb_event_hook_t *hook)
01483 {
01484     while (hook) {
01485         rb_gc_mark(hook->data);
01486         hook = hook->next;
01487     }
01488 }
01489 
01490 void
01491 rb_vm_mark(void *ptr)
01492 {
01493     int i;
01494 
01495     RUBY_MARK_ENTER("vm");
01496     RUBY_GC_INFO("-------------------------------------------------\n");
01497     if (ptr) {
01498         rb_vm_t *vm = ptr;
01499         if (vm->living_threads) {
01500             st_foreach(vm->living_threads, vm_mark_each_thread_func, 0);
01501         }
01502         RUBY_MARK_UNLESS_NULL(vm->thgroup_default);
01503         RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
01504         RUBY_MARK_UNLESS_NULL(vm->load_path);
01505         RUBY_MARK_UNLESS_NULL(vm->loaded_features);
01506         RUBY_MARK_UNLESS_NULL(vm->top_self);
01507         RUBY_MARK_UNLESS_NULL(vm->coverages);
01508         rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count);
01509 
01510         if (vm->loading_table) {
01511             rb_mark_tbl(vm->loading_table);
01512         }
01513 
01514         mark_event_hooks(vm->event_hooks);
01515 
01516         for (i = 0; i < RUBY_NSIG; i++) {
01517             if (vm->trap_list[i].cmd)
01518                 rb_gc_mark(vm->trap_list[i].cmd);
01519         }
01520     }
01521 
01522     RUBY_MARK_LEAVE("vm");
01523 }
01524 
01525 #define vm_free 0
01526 
01527 int
01528 ruby_vm_destruct(void *ptr)
01529 {
01530     RUBY_FREE_ENTER("vm");
01531     if (ptr) {
01532         rb_vm_t *vm = ptr;
01533         rb_thread_t *th = vm->main_thread;
01534 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
01535         struct rb_objspace *objspace = vm->objspace;
01536 #endif
01537         rb_gc_force_recycle(vm->self);
01538         vm->main_thread = 0;
01539         if (th) {
01540             thread_free(th);
01541         }
01542         if (vm->living_threads) {
01543             st_free_table(vm->living_threads);
01544             vm->living_threads = 0;
01545         }
01546         rb_thread_lock_unlock(&vm->global_vm_lock);
01547         rb_thread_lock_destroy(&vm->global_vm_lock);
01548         ruby_xfree(vm);
01549         ruby_current_vm = 0;
01550 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
01551         if (objspace) {
01552             rb_objspace_free(objspace);
01553         }
01554 #endif
01555     }
01556     RUBY_FREE_LEAVE("vm");
01557     return 0;
01558 }
01559 
01560 static size_t
01561 vm_memsize(const void *ptr)
01562 {
01563     if (ptr) {
01564         const rb_vm_t *vmobj = ptr;
01565         return sizeof(rb_vm_t) + st_memsize(vmobj->living_threads);
01566     }
01567     else {
01568         return 0;
01569     }
01570 }
01571 
01572 static const rb_data_type_t vm_data_type = {
01573     "VM",
01574     rb_vm_mark, vm_free, vm_memsize,
01575 };
01576 
01577 static void
01578 vm_init2(rb_vm_t *vm)
01579 {
01580     MEMZERO(vm, rb_vm_t, 1);
01581     vm->src_encoding_index = -1;
01582 }
01583 
01584 /* Thread */
01585 
01586 #define USE_THREAD_DATA_RECYCLE 1
01587 
01588 #if USE_THREAD_DATA_RECYCLE
01589 #define RECYCLE_MAX 64
01590 static VALUE *thread_recycle_stack_slot[RECYCLE_MAX];
01591 static int thread_recycle_stack_count = 0;
01592 
01593 static VALUE *
01594 thread_recycle_stack(size_t size)
01595 {
01596     if (thread_recycle_stack_count) {
01597         return thread_recycle_stack_slot[--thread_recycle_stack_count];
01598     }
01599     else {
01600         return ALLOC_N(VALUE, size);
01601     }
01602 }
01603 
01604 #else
01605 #define thread_recycle_stack(size) ALLOC_N(VALUE, (size))
01606 #endif
01607 
01608 void
01609 rb_thread_recycle_stack_release(VALUE *stack)
01610 {
01611 #if USE_THREAD_DATA_RECYCLE
01612     if (thread_recycle_stack_count < RECYCLE_MAX) {
01613         thread_recycle_stack_slot[thread_recycle_stack_count++] = stack;
01614         return;
01615     }
01616 #endif
01617     ruby_xfree(stack);
01618 }
01619 
01620 #ifdef USE_THREAD_RECYCLE
01621 static rb_thread_t *
01622 thread_recycle_struct(void)
01623 {
01624     void *p = ALLOC_N(rb_thread_t, 1);
01625     memset(p, 0, sizeof(rb_thread_t));
01626     return p;
01627 }
01628 #endif
01629 
01630 void rb_gc_mark_machine_stack(rb_thread_t *th);
01631 
01632 void
01633 rb_thread_mark(void *ptr)
01634 {
01635     rb_thread_t *th = NULL;
01636     RUBY_MARK_ENTER("thread");
01637     if (ptr) {
01638         th = ptr;
01639         if (th->stack) {
01640             VALUE *p = th->stack;
01641             VALUE *sp = th->cfp->sp;
01642             rb_control_frame_t *cfp = th->cfp;
01643             rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
01644 
01645             while (p < sp) {
01646                 rb_gc_mark(*p++);
01647             }
01648             rb_gc_mark_locations(p, p + th->mark_stack_len);
01649 
01650             while (cfp != limit_cfp) {
01651                 rb_iseq_t *iseq = cfp->iseq;
01652                 rb_gc_mark(cfp->proc);
01653                 rb_gc_mark(cfp->self);
01654                 if (iseq) {
01655                     rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq);
01656                 }
01657                 if (cfp->me) ((rb_method_entry_t *)cfp->me)->mark = 1;
01658                 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
01659             }
01660         }
01661 
01662         /* mark ruby objects */
01663         RUBY_MARK_UNLESS_NULL(th->first_proc);
01664         if (th->first_proc) RUBY_MARK_UNLESS_NULL(th->first_args);
01665 
01666         RUBY_MARK_UNLESS_NULL(th->thgroup);
01667         RUBY_MARK_UNLESS_NULL(th->value);
01668         RUBY_MARK_UNLESS_NULL(th->errinfo);
01669         RUBY_MARK_UNLESS_NULL(th->thrown_errinfo);
01670         RUBY_MARK_UNLESS_NULL(th->local_svar);
01671         RUBY_MARK_UNLESS_NULL(th->top_self);
01672         RUBY_MARK_UNLESS_NULL(th->top_wrapper);
01673         RUBY_MARK_UNLESS_NULL(th->fiber);
01674         RUBY_MARK_UNLESS_NULL(th->root_fiber);
01675         RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
01676         RUBY_MARK_UNLESS_NULL(th->last_status);
01677 
01678         RUBY_MARK_UNLESS_NULL(th->locking_mutex);
01679 
01680         rb_mark_tbl(th->local_storage);
01681 
01682         if (GET_THREAD() != th && th->machine_stack_start && th->machine_stack_end) {
01683             rb_gc_mark_machine_stack(th);
01684             rb_gc_mark_locations((VALUE *)&th->machine_regs,
01685                                  (VALUE *)(&th->machine_regs) +
01686                                  sizeof(th->machine_regs) / sizeof(VALUE));
01687         }
01688 
01689         mark_event_hooks(th->event_hooks);
01690     }
01691 
01692     RUBY_MARK_LEAVE("thread");
01693 }
01694 
01695 static void
01696 thread_free(void *ptr)
01697 {
01698     rb_thread_t *th;
01699     RUBY_FREE_ENTER("thread");
01700 
01701     if (ptr) {
01702         th = ptr;
01703 
01704         if (!th->root_fiber) {
01705             RUBY_FREE_UNLESS_NULL(th->stack);
01706         }
01707 
01708         if (th->locking_mutex != Qfalse) {
01709             rb_bug("thread_free: locking_mutex must be NULL (%p:%ld)", (void *)th, th->locking_mutex);
01710         }
01711         if (th->keeping_mutexes != NULL) {
01712             rb_bug("thread_free: keeping_mutexes must be NULL (%p:%p)", (void *)th, th->keeping_mutexes);
01713         }
01714 
01715         if (th->local_storage) {
01716             st_free_table(th->local_storage);
01717         }
01718 
01719 #if USE_VALUE_CACHE
01720         {
01721             VALUE *ptr = th->value_cache_ptr;
01722             while (*ptr) {
01723                 VALUE v = *ptr;
01724                 RBASIC(v)->flags = 0;
01725                 RBASIC(v)->klass = 0;
01726                 ptr++;
01727             }
01728         }
01729 #endif
01730 
01731         if (th->vm && th->vm->main_thread == th) {
01732             RUBY_GC_INFO("main thread\n");
01733         }
01734         else {
01735 #ifdef USE_SIGALTSTACK
01736             if (th->altstack) {
01737                 free(th->altstack);
01738             }
01739 #endif
01740             ruby_xfree(ptr);
01741         }
01742     }
01743     RUBY_FREE_LEAVE("thread");
01744 }
01745 
01746 static size_t
01747 thread_memsize(const void *ptr)
01748 {
01749     if (ptr) {
01750         const rb_thread_t *th = ptr;
01751         size_t size = sizeof(rb_thread_t);
01752 
01753         if (!th->root_fiber) {
01754             size += th->stack_size * sizeof(VALUE);
01755         }
01756         if (th->local_storage) {
01757             st_memsize(th->local_storage);
01758         }
01759         return size;
01760     }
01761     else {
01762         return 0;
01763     }
01764 }
01765 
01766 static const rb_data_type_t thread_data_type = {
01767     "VM/thread",
01768     rb_thread_mark,
01769     thread_free,
01770     thread_memsize,
01771 };
01772 
01773 static VALUE
01774 thread_alloc(VALUE klass)
01775 {
01776     VALUE volatile obj;
01777 #ifdef USE_THREAD_RECYCLE
01778     rb_thread_t *th = thread_recycle_struct();
01779     obj = TypedData_Wrap_Struct(klass, &thread_data_type, th);
01780 #else
01781     rb_thread_t *th;
01782     obj = TypedData_Make_Struct(klass, rb_thread_t, &thread_data_type, th);
01783 #endif
01784     return obj;
01785 }
01786 
01787 static void
01788 th_init2(rb_thread_t *th, VALUE self)
01789 {
01790     th->self = self;
01791 
01792     /* allocate thread stack */
01793     th->stack_size = RUBY_VM_THREAD_STACK_SIZE;
01794     th->stack = thread_recycle_stack(th->stack_size);
01795 
01796     th->cfp = (void *)(th->stack + th->stack_size);
01797 
01798     vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, 0, 0,
01799                   th->stack, 0, 1);
01800 
01801     th->status = THREAD_RUNNABLE;
01802     th->errinfo = Qnil;
01803     th->last_status = Qnil;
01804 
01805 #if USE_VALUE_CACHE
01806     th->value_cache_ptr = &th->value_cache[0];
01807 #endif
01808 }
01809 
01810 static void
01811 th_init(rb_thread_t *th, VALUE self)
01812 {
01813     th_init2(th, self);
01814 }
01815 
01816 static VALUE
01817 ruby_thread_init(VALUE self)
01818 {
01819     rb_thread_t *th;
01820     rb_vm_t *vm = GET_THREAD()->vm;
01821     GetThreadPtr(self, th);
01822 
01823     th_init(th, self);
01824     th->vm = vm;
01825 
01826     th->top_wrapper = 0;
01827     th->top_self = rb_vm_top_self();
01828     return self;
01829 }
01830 
01831 VALUE
01832 rb_thread_alloc(VALUE klass)
01833 {
01834     VALUE self = thread_alloc(klass);
01835     ruby_thread_init(self);
01836     return self;
01837 }
01838 
01839 static void
01840 vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
01841                  rb_num_t is_singleton, NODE *cref)
01842 {
01843     VALUE klass = cref->nd_clss;
01844     int noex = (int)cref->nd_visi;
01845     rb_iseq_t *miseq;
01846     GetISeqPtr(iseqval, miseq);
01847 
01848     if (NIL_P(klass)) {
01849         rb_raise(rb_eTypeError, "no class/module to add method");
01850     }
01851 
01852     if (is_singleton) {
01853         if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
01854             rb_raise(rb_eTypeError,
01855                      "can't define singleton method \"%s\" for %s",
01856                      rb_id2name(id), rb_obj_classname(obj));
01857         }
01858 
01859         if (OBJ_FROZEN(obj)) {
01860             rb_error_frozen("object");
01861         }
01862 
01863         klass = rb_singleton_class(obj);
01864         noex = NOEX_PUBLIC;
01865     }
01866 
01867     /* dup */
01868     COPY_CREF(miseq->cref_stack, cref);
01869     miseq->klass = klass;
01870     miseq->defined_method_id = id;
01871     rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
01872 
01873     if (!is_singleton && noex == NOEX_MODFUNC) {
01874         rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
01875     }
01876     INC_VM_STATE_VERSION();
01877 }
01878 
01879 #define REWIND_CFP(expr) do { \
01880     rb_thread_t *th__ = GET_THREAD(); \
01881     th__->cfp++; expr; th__->cfp--; \
01882 } while (0)
01883 
01884 static VALUE
01885 m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
01886 {
01887     REWIND_CFP({
01888         vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
01889     });
01890     return Qnil;
01891 }
01892 
01893 static VALUE
01894 m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
01895 {
01896     REWIND_CFP({
01897         vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
01898     });
01899     return Qnil;
01900 }
01901 
01902 static VALUE
01903 m_core_set_method_alias(VALUE self, VALUE cbase, VALUE sym1, VALUE sym2)
01904 {
01905     REWIND_CFP({
01906         rb_alias(cbase, SYM2ID(sym1), SYM2ID(sym2));
01907     });
01908     return Qnil;
01909 }
01910 
01911 static VALUE
01912 m_core_set_variable_alias(VALUE self, VALUE sym1, VALUE sym2)
01913 {
01914     REWIND_CFP({
01915         rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
01916     });
01917     return Qnil;
01918 }
01919 
01920 static VALUE
01921 m_core_undef_method(VALUE self, VALUE cbase, VALUE sym)
01922 {
01923     REWIND_CFP({
01924         rb_undef(cbase, SYM2ID(sym));
01925         INC_VM_STATE_VERSION();
01926     });
01927     return Qnil;
01928 }
01929 
01930 static VALUE
01931 m_core_set_postexe(VALUE self, VALUE iseqval)
01932 {
01933     REWIND_CFP({
01934         rb_iseq_t *blockiseq;
01935         rb_block_t *blockptr;
01936         rb_thread_t *th = GET_THREAD();
01937         rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
01938         VALUE proc;
01939         extern void rb_call_end_proc(VALUE data);
01940 
01941         GetISeqPtr(iseqval, blockiseq);
01942 
01943         blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
01944         blockptr->iseq = blockiseq;
01945         blockptr->proc = 0;
01946 
01947         proc = rb_vm_make_proc(th, blockptr, rb_cProc);
01948         rb_set_end_proc(rb_call_end_proc, proc);
01949     });
01950     return Qnil;
01951 }
01952 
01953 extern VALUE *rb_gc_stack_start;
01954 extern size_t rb_gc_stack_maxsize;
01955 #ifdef __ia64
01956 extern VALUE *rb_gc_register_stack_start;
01957 #endif
01958 
01959 /* debug functions */
01960 
01961 /* :nodoc: */
01962 static VALUE
01963 sdr(void)
01964 {
01965     rb_vm_bugreport();
01966     return Qnil;
01967 }
01968 
01969 /* :nodoc: */
01970 static VALUE
01971 nsdr(void)
01972 {
01973     VALUE ary = rb_ary_new();
01974 #if HAVE_BACKTRACE
01975 #include <execinfo.h>
01976 #define MAX_NATIVE_TRACE 1024
01977     static void *trace[MAX_NATIVE_TRACE];
01978     int n = backtrace(trace, MAX_NATIVE_TRACE);
01979     char **syms = backtrace_symbols(trace, n);
01980     int i;
01981 
01982     if (syms == 0) {
01983         rb_memerror();
01984     }
01985 
01986     for (i=0; i<n; i++) {
01987         rb_ary_push(ary, rb_str_new2(syms[i]));
01988     }
01989     free(syms); /* OK */
01990 #endif
01991     return ary;
01992 }
01993 
01994 void
01995 Init_VM(void)
01996 {
01997     VALUE opts;
01998     VALUE klass;
01999     VALUE fcore;
02000 
02001     /* ::VM */
02002     rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);
02003     rb_undef_alloc_func(rb_cRubyVM);
02004     rb_undef_method(CLASS_OF(rb_cRubyVM), "new");
02005 
02006     /* ::VM::FrozenCore */
02007     fcore = rb_class_new(rb_cBasicObject);
02008     RBASIC(fcore)->flags = T_ICLASS;
02009     klass = rb_singleton_class(fcore);
02010     rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
02011     rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
02012     rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
02013     rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
02014     rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
02015     rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1);
02016     rb_obj_freeze(fcore);
02017     rb_gc_register_mark_object(fcore);
02018     rb_mRubyVMFrozenCore = fcore;
02019 
02020     /* ::VM::Env */
02021     rb_cEnv = rb_define_class_under(rb_cRubyVM, "Env", rb_cObject);
02022     rb_undef_alloc_func(rb_cEnv);
02023     rb_undef_method(CLASS_OF(rb_cEnv), "new");
02024 
02025     /* ::Thread */
02026     rb_cThread = rb_define_class("Thread", rb_cObject);
02027     rb_undef_alloc_func(rb_cThread);
02028 
02029     /* ::VM::USAGE_ANALYSIS_* */
02030     rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_INSN", rb_hash_new());
02031     rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_REGS", rb_hash_new());
02032     rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_INSN_BIGRAM", rb_hash_new());
02033     rb_define_const(rb_cRubyVM, "OPTS", opts = rb_ary_new());
02034 
02035 #if   OPT_DIRECT_THREADED_CODE
02036     rb_ary_push(opts, rb_str_new2("direct threaded code"));
02037 #elif OPT_TOKEN_THREADED_CODE
02038     rb_ary_push(opts, rb_str_new2("token threaded code"));
02039 #elif OPT_CALL_THREADED_CODE
02040     rb_ary_push(opts, rb_str_new2("call threaded code"));
02041 #endif
02042 
02043 #if OPT_BASIC_OPERATIONS
02044     rb_ary_push(opts, rb_str_new2("optimize basic operation"));
02045 #endif
02046 
02047 #if OPT_STACK_CACHING
02048     rb_ary_push(opts, rb_str_new2("stack caching"));
02049 #endif
02050 #if OPT_OPERANDS_UNIFICATION
02051     rb_ary_push(opts, rb_str_new2("operands unification]"));
02052 #endif
02053 #if OPT_INSTRUCTIONS_UNIFICATION
02054     rb_ary_push(opts, rb_str_new2("instructions unification"));
02055 #endif
02056 #if OPT_INLINE_METHOD_CACHE
02057     rb_ary_push(opts, rb_str_new2("inline method cache"));
02058 #endif
02059 #if OPT_BLOCKINLINING
02060     rb_ary_push(opts, rb_str_new2("block inlining"));
02061 #endif
02062 
02063     /* ::VM::InsnNameArray */
02064     rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", rb_insns_name_array());
02065 
02066     /* debug functions ::VM::SDR(), ::VM::NSDR() */
02067 #if VMDEBUG
02068     rb_define_singleton_method(rb_cRubyVM, "SDR", sdr, 0);
02069     rb_define_singleton_method(rb_cRubyVM, "NSDR", nsdr, 0);
02070 #else
02071     (void)sdr;
02072     (void)nsdr;
02073 #endif
02074 
02075     /* VM bootstrap: phase 2 */
02076     {
02077         rb_vm_t *vm = ruby_current_vm;
02078         rb_thread_t *th = GET_THREAD();
02079         VALUE filename = rb_str_new2("<main>");
02080         volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
02081         volatile VALUE th_self;
02082         rb_iseq_t *iseq;
02083 
02084         /* create vm object */
02085         vm->self = TypedData_Wrap_Struct(rb_cRubyVM, &vm_data_type, vm);
02086 
02087         /* create main thread */
02088         th_self = th->self = TypedData_Wrap_Struct(rb_cThread, &thread_data_type, th);
02089         vm->main_thread = th;
02090         vm->running_thread = th;
02091         th->vm = vm;
02092         th->top_wrapper = 0;
02093         th->top_self = rb_vm_top_self();
02094         rb_thread_set_current(th);
02095 
02096         vm->living_threads = st_init_numtable();
02097         st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id);
02098 
02099         rb_gc_register_mark_object(iseqval);
02100         GetISeqPtr(iseqval, iseq);
02101         th->cfp->iseq = iseq;
02102         th->cfp->pc = iseq->iseq_encoded;
02103         th->cfp->self = th->top_self;
02104 
02105         rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
02106     }
02107     vm_init_redefined_flag();
02108 }
02109 
02110 void
02111 rb_vm_set_progname(VALUE filename)
02112 {
02113     rb_thread_t *th = GET_VM()->main_thread;
02114     rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
02115     --cfp;
02116     cfp->iseq->filename = filename;
02117 }
02118 
02119 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
02120 struct rb_objspace *rb_objspace_alloc(void);
02121 #endif
02122 void ruby_thread_init_stack(rb_thread_t *th);
02123 
02124 extern void Init_native_thread(void);
02125 
02126 void
02127 Init_BareVM(void)
02128 {
02129     /* VM bootstrap: phase 1 */
02130     rb_vm_t * vm = malloc(sizeof(*vm));
02131     rb_thread_t * th = malloc(sizeof(*th));
02132     if (!vm || !th) {
02133         fprintf(stderr, "[FATAL] failed to allocate memory\n");
02134         exit(EXIT_FAILURE);
02135     }
02136     MEMZERO(th, rb_thread_t, 1);
02137 
02138     rb_thread_set_current_raw(th);
02139 
02140     vm_init2(vm);
02141 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
02142     vm->objspace = rb_objspace_alloc();
02143 #endif
02144     ruby_current_vm = vm;
02145 
02146     Init_native_thread();
02147     th_init2(th, 0);
02148     th->vm = vm;
02149     ruby_thread_init_stack(th);
02150 }
02151 
02152 /* top self */
02153 
02154 static VALUE
02155 main_to_s(VALUE obj)
02156 {
02157     return rb_str_new2("main");
02158 }
02159 
02160 VALUE
02161 rb_vm_top_self(void)
02162 {
02163     return GET_VM()->top_self;
02164 }
02165 
02166 void
02167 Init_top_self(void)
02168 {
02169     rb_vm_t *vm = GET_VM();
02170 
02171     vm->top_self = rb_obj_alloc(rb_cObject);
02172     rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
02173 
02174     /* initialize mark object array */
02175     vm->mark_object_ary = rb_ary_tmp_new(1);
02176 }
02177 
02178 VALUE *
02179 ruby_vm_verbose_ptr(rb_vm_t *vm)
02180 {
02181     return &vm->verbose;
02182 }
02183 
02184 VALUE *
02185 ruby_vm_debug_ptr(rb_vm_t *vm)
02186 {
02187     return &vm->debug;
02188 }
02189 
02190 VALUE *
02191 rb_ruby_verbose_ptr(void)
02192 {
02193     return ruby_vm_verbose_ptr(GET_VM());
02194 }
02195 
02196 VALUE *
02197 rb_ruby_debug_ptr(void)
02198 {
02199     return ruby_vm_debug_ptr(GET_VM());
02200 }
02201 

Generated on Wed Aug 10 09:17:16 2011 for Ruby by  doxygen 1.4.7