|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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 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 rb_class2name(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
1.7.3