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