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