1/********************************************************************** 2 3 vm.c - 4 5 $Author: nagachika $ 6 7 Copyright (C) 2004-2007 Koichi Sasada 8 9**********************************************************************/ 10 11#include "ruby/ruby.h" 12#include "ruby/vm.h" 13#include "ruby/st.h" 14#include "ruby/encoding.h" 15#include "internal.h" 16 17#include "gc.h" 18#include "vm_core.h" 19#include "iseq.h" 20#include "eval_intern.h" 21#include "probes.h" 22#include "probes_helper.h" 23 24static inline VALUE * 25VM_EP_LEP(VALUE *ep) 26{ 27 while (1) { 28 if (VM_EP_LEP_P(ep)) { 29 return ep; 30 } 31 ep = VM_EP_PREV_EP(ep); 32 } 33} 34 35VALUE * 36rb_vm_ep_local_ep(VALUE *ep) 37{ 38 return VM_EP_LEP(ep); 39} 40 41static inline VALUE * 42VM_CF_LEP(rb_control_frame_t *cfp) 43{ 44 return VM_EP_LEP(cfp->ep); 45} 46 47static inline VALUE * 48VM_CF_PREV_EP(rb_control_frame_t * cfp) 49{ 50 return VM_EP_PREV_EP((cfp)->ep); 51} 52 53static inline rb_block_t * 54VM_CF_BLOCK_PTR(rb_control_frame_t *cfp) 55{ 56 VALUE *ep = VM_CF_LEP(cfp); 57 return VM_EP_BLOCK_PTR(ep); 58} 59 60rb_block_t * 61rb_vm_control_frame_block_ptr(rb_control_frame_t *cfp) 62{ 63 return VM_CF_BLOCK_PTR(cfp); 64} 65 66#if VM_COLLECT_USAGE_DETAILS 67static void vm_collect_usage_operand(int insn, int n, VALUE op); 68static void vm_collect_usage_insn(int insn); 69static void vm_collect_usage_register(int reg, int isset); 70#endif 71 72static VALUE 73vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, 74 int argc, const VALUE *argv, const rb_block_t *blockptr); 75 76#include "vm_insnhelper.h" 77#include "vm_insnhelper.c" 78#include "vm_exec.h" 79#include "vm_exec.c" 80 81#include "vm_method.c" 82#include "vm_eval.c" 83 84#include <assert.h> 85 86#define BUFSIZE 0x100 87#define PROCDEBUG 0 88 89VALUE rb_cRubyVM; 90VALUE rb_cThread; 91VALUE rb_cEnv; 92VALUE rb_mRubyVMFrozenCore; 93 94VALUE ruby_vm_const_missing_count = 0; 95char ruby_vm_redefined_flag[BOP_LAST_]; 96rb_thread_t *ruby_current_thread = 0; 97rb_vm_t *ruby_current_vm = 0; 98rb_event_flag_t ruby_vm_event_flags; 99 100static void thread_free(void *ptr); 101 102void 103rb_vm_change_state(void) 104{ 105 INC_VM_STATE_VERSION(); 106} 107 108static void vm_clear_global_method_cache(void); 109 110static void 111vm_clear_all_inline_method_cache(void) 112{ 113 /* TODO: Clear all inline cache entries in all iseqs. 114 How to iterate all iseqs in sweep phase? 115 rb_objspace_each_objects() doesn't work at sweep phase. 116 */ 117} 118 119static void 120vm_clear_all_cache() 121{ 122 vm_clear_global_method_cache(); 123 vm_clear_all_inline_method_cache(); 124 ruby_vm_global_state_version = 1; 125} 126 127void 128rb_vm_inc_const_missing_count(void) 129{ 130 ruby_vm_const_missing_count +=1; 131} 132 133/* control stack frame */ 134 135static void 136vm_set_top_stack(rb_thread_t * th, VALUE iseqval) 137{ 138 rb_iseq_t *iseq; 139 GetISeqPtr(iseqval, iseq); 140 141 if (iseq->type != ISEQ_TYPE_TOP) { 142 rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence"); 143 } 144 145 /* for return */ 146 CHECK_VM_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max); 147 vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, 148 th->top_self, rb_cObject, VM_ENVVAL_BLOCK_PTR(0), 149 iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0); 150} 151 152static void 153vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t *base_block) 154{ 155 rb_iseq_t *iseq; 156 GetISeqPtr(iseqval, iseq); 157 158 CHECK_VM_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max); 159 vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, 160 base_block->self, base_block->klass, 161 VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded, 162 th->cfp->sp, iseq->local_size, 0); 163 164 if (cref) { 165 th->cfp->ep[-1] = (VALUE)cref; 166 } 167} 168 169static void 170vm_set_main_stack(rb_thread_t *th, VALUE iseqval) 171{ 172 VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")); 173 rb_binding_t *bind; 174 rb_iseq_t *iseq; 175 rb_env_t *env; 176 177 GetBindingPtr(toplevel_binding, bind); 178 GetEnvPtr(bind->env, env); 179 vm_set_eval_stack(th, iseqval, 0, &env->block); 180 181 /* save binding */ 182 GetISeqPtr(iseqval, iseq); 183 if (bind && iseq->local_size > 0) { 184 bind->env = rb_vm_make_env_object(th, th->cfp); 185 } 186} 187 188rb_control_frame_t * 189rb_vm_get_binding_creatable_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp) 190{ 191 while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 192 if (cfp->iseq) { 193 return (rb_control_frame_t *)cfp; 194 } 195 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 196 } 197 return 0; 198} 199 200rb_control_frame_t * 201rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp) 202{ 203 while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 204 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 205 return (rb_control_frame_t *)cfp; 206 } 207 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 208 } 209 return 0; 210} 211 212static rb_control_frame_t * 213vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp) 214{ 215 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 216 return cfp; 217 } 218 219 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 220 221 while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 222 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 223 return cfp; 224 } 225 226 if ((cfp->flag & VM_FRAME_FLAG_PASSED) == 0) { 227 break; 228 } 229 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 230 } 231 return 0; 232} 233 234/* at exit */ 235 236void 237ruby_vm_at_exit(void (*func)(rb_vm_t *)) 238{ 239 rb_ary_push((VALUE)&GET_VM()->at_exit, (VALUE)func); 240} 241 242static void 243ruby_vm_run_at_exit_hooks(rb_vm_t *vm) 244{ 245 VALUE hook = (VALUE)&vm->at_exit; 246 247 while (RARRAY_LEN(hook) > 0) { 248 typedef void rb_vm_at_exit_func(rb_vm_t*); 249 rb_vm_at_exit_func *func = (rb_vm_at_exit_func*)rb_ary_pop(hook); 250 (*func)(vm); 251 } 252 rb_ary_free(hook); 253} 254 255/* Env */ 256 257/* 258 env{ 259 env[0] // special (block or prev env) 260 env[1] // env object 261 }; 262 */ 263 264#define ENV_IN_HEAP_P(th, env) \ 265 (!((th)->stack <= (env) && (env) < ((th)->stack + (th)->stack_size))) 266#define ENV_VAL(env) ((env)[1]) 267 268static void 269env_mark(void * const ptr) 270{ 271 RUBY_MARK_ENTER("env"); 272 if (ptr) { 273 const rb_env_t * const env = ptr; 274 275 if (env->env) { 276 /* TODO: should mark more restricted range */ 277 RUBY_GC_INFO("env->env\n"); 278 rb_gc_mark_locations(env->env, env->env + env->env_size); 279 } 280 281 RUBY_GC_INFO("env->prev_envval\n"); 282 RUBY_MARK_UNLESS_NULL(env->prev_envval); 283 RUBY_MARK_UNLESS_NULL(env->block.self); 284 RUBY_MARK_UNLESS_NULL(env->block.proc); 285 286 if (env->block.iseq) { 287 if (BUILTIN_TYPE(env->block.iseq) == T_NODE) { 288 RUBY_MARK_UNLESS_NULL((VALUE)env->block.iseq); 289 } 290 else { 291 RUBY_MARK_UNLESS_NULL(env->block.iseq->self); 292 } 293 } 294 } 295 RUBY_MARK_LEAVE("env"); 296} 297 298static void 299env_free(void * const ptr) 300{ 301 RUBY_FREE_ENTER("env"); 302 if (ptr) { 303 rb_env_t *const env = ptr; 304 RUBY_FREE_UNLESS_NULL(env->env); 305 ruby_xfree(ptr); 306 } 307 RUBY_FREE_LEAVE("env"); 308} 309 310static size_t 311env_memsize(const void *ptr) 312{ 313 if (ptr) { 314 const rb_env_t * const env = ptr; 315 size_t size = sizeof(rb_env_t); 316 if (env->env) { 317 size += env->env_size * sizeof(VALUE); 318 } 319 return size; 320 } 321 return 0; 322} 323 324static const rb_data_type_t env_data_type = { 325 "VM/env", 326 {env_mark, env_free, env_memsize,}, 327}; 328 329static VALUE 330env_alloc(void) 331{ 332 VALUE obj; 333 rb_env_t *env; 334 obj = TypedData_Make_Struct(rb_cEnv, rb_env_t, &env_data_type, env); 335 env->env = 0; 336 env->prev_envval = 0; 337 env->block.iseq = 0; 338 return obj; 339} 340 341static VALUE check_env_value(VALUE envval); 342 343static int 344check_env(rb_env_t * const env) 345{ 346 fprintf(stderr, "---\n"); 347 fprintf(stderr, "envptr: %p\n", (void *)&env->block.ep[0]); 348 fprintf(stderr, "envval: %10p ", (void *)env->block.ep[1]); 349 dp(env->block.ep[1]); 350 fprintf(stderr, "ep: %10p\n", (void *)env->block.ep); 351 if (env->prev_envval) { 352 fprintf(stderr, ">>\n"); 353 check_env_value(env->prev_envval); 354 fprintf(stderr, "<<\n"); 355 } 356 return 1; 357} 358 359static VALUE 360check_env_value(VALUE envval) 361{ 362 rb_env_t *env; 363 GetEnvPtr(envval, env); 364 365 if (check_env(env)) { 366 return envval; 367 } 368 rb_bug("invalid env"); 369 return Qnil; /* unreachable */ 370} 371 372static VALUE 373vm_make_env_each(rb_thread_t * const th, rb_control_frame_t * const cfp, 374 VALUE *envptr, VALUE * const endptr) 375{ 376 VALUE envval, penvval = 0; 377 rb_env_t *env; 378 VALUE *nenvptr; 379 int i, local_size; 380 381 if (ENV_IN_HEAP_P(th, envptr)) { 382 return ENV_VAL(envptr); 383 } 384 385 if (envptr != endptr) { 386 VALUE *penvptr = GC_GUARDED_PTR_REF(*envptr); 387 rb_control_frame_t *pcfp = cfp; 388 389 if (ENV_IN_HEAP_P(th, penvptr)) { 390 penvval = ENV_VAL(penvptr); 391 } 392 else { 393 while (pcfp->ep != penvptr) { 394 pcfp++; 395 if (pcfp->ep == 0) { 396 SDR(); 397 rb_bug("invalid ep"); 398 } 399 } 400 penvval = vm_make_env_each(th, pcfp, penvptr, endptr); 401 *envptr = VM_ENVVAL_PREV_EP_PTR(pcfp->ep); 402 } 403 } 404 405 /* allocate env */ 406 envval = env_alloc(); 407 GetEnvPtr(envval, env); 408 409 if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 410 local_size = 2; 411 } 412 else { 413 local_size = cfp->iseq->local_size; 414 } 415 416 env->env_size = local_size + 1 + 1; 417 env->local_size = local_size; 418 env->env = ALLOC_N(VALUE, env->env_size); 419 env->prev_envval = penvval; 420 421 for (i = 0; i <= local_size; i++) { 422 env->env[i] = envptr[-local_size + i]; 423#if 0 424 fprintf(stderr, "%2d ", &envptr[-local_size + i] - th->stack); dp(env->env[i]); 425 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 426 /* clear value stack for GC */ 427 envptr[-local_size + i] = 0; 428 } 429#endif 430 } 431 432 *envptr = envval; /* GC mark */ 433 nenvptr = &env->env[i - 1]; 434 nenvptr[1] = envval; /* frame self */ 435 436 /* reset ep in cfp */ 437 cfp->ep = nenvptr; 438 439 /* as Binding */ 440 env->block.self = cfp->self; 441 env->block.ep = cfp->ep; 442 env->block.iseq = cfp->iseq; 443 444 if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 445 /* TODO */ 446 env->block.iseq = 0; 447 } 448 return envval; 449} 450 451static int 452collect_local_variables_in_iseq(rb_iseq_t *iseq, const VALUE ary) 453{ 454 int i; 455 if (!iseq) return 0; 456 for (i = 0; i < iseq->local_table_size; i++) { 457 ID lid = iseq->local_table[i]; 458 if (rb_is_local_id(lid)) { 459 rb_ary_push(ary, ID2SYM(lid)); 460 } 461 } 462 return 1; 463} 464 465static int 466collect_local_variables_in_env(rb_env_t * env, const VALUE ary) 467{ 468 469 while (collect_local_variables_in_iseq(env->block.iseq, ary), 470 env->prev_envval) { 471 GetEnvPtr(env->prev_envval, env); 472 } 473 return 0; 474} 475 476static int 477vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *ep, VALUE ary) 478{ 479 if (ENV_IN_HEAP_P(th, ep)) { 480 rb_env_t *env; 481 GetEnvPtr(ENV_VAL(ep), env); 482 collect_local_variables_in_env(env, ary); 483 return 1; 484 } 485 else { 486 return 0; 487 } 488} 489 490static void vm_rewrite_ep_in_errinfo(rb_thread_t *th); 491static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block); 492static VALUE vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp, VALUE *blockprocptr); 493 494VALUE 495rb_vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp) 496{ 497 VALUE blockprocval; 498 return vm_make_env_object(th, cfp, &blockprocval); 499} 500 501static VALUE 502vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp, VALUE *blockprocptr) 503{ 504 VALUE envval; 505 VALUE *lep = VM_CF_LEP(cfp); 506 rb_block_t *blockptr = VM_EP_BLOCK_PTR(lep); 507 508 if (blockptr) { 509 VALUE blockprocval = vm_make_proc_from_block(th, blockptr); 510 rb_proc_t *p; 511 GetProcPtr(blockprocval, p); 512 lep[0] = VM_ENVVAL_BLOCK_PTR(&p->block); 513 *blockprocptr = blockprocval; 514 } 515 516 envval = vm_make_env_each(th, cfp, cfp->ep, lep); 517 vm_rewrite_ep_in_errinfo(th); 518 519 if (PROCDEBUG) { 520 check_env_value(envval); 521 } 522 523 return envval; 524} 525 526static void 527vm_rewrite_ep_in_errinfo(rb_thread_t *th) 528{ 529 rb_control_frame_t *cfp = th->cfp; 530 while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 531 /* rewrite ep in errinfo to point to heap */ 532 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) && 533 (cfp->iseq->type == ISEQ_TYPE_RESCUE || 534 cfp->iseq->type == ISEQ_TYPE_ENSURE)) { 535 VALUE errinfo = cfp->ep[-2]; /* #$! */ 536 if (RB_TYPE_P(errinfo, T_NODE)) { 537 VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(errinfo); 538 if (! ENV_IN_HEAP_P(th, escape_ep)) { 539 VALUE epval = *escape_ep; 540 if (!SPECIAL_CONST_P(epval) && RBASIC(epval)->klass == rb_cEnv) { 541 rb_env_t *epenv; 542 GetEnvPtr(epval, epenv); 543 SET_THROWOBJ_CATCH_POINT(errinfo, (VALUE)(epenv->env + epenv->local_size)); 544 } 545 } 546 } 547 } 548 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 549 } 550} 551 552void 553rb_vm_stack_to_heap(rb_thread_t *th) 554{ 555 rb_control_frame_t *cfp = th->cfp; 556 while ((cfp = rb_vm_get_binding_creatable_next_cfp(th, cfp)) != 0) { 557 rb_vm_make_env_object(th, cfp); 558 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 559 } 560} 561 562/* Proc */ 563 564static VALUE 565vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block) 566{ 567 if (!block->proc) { 568 block->proc = rb_vm_make_proc(th, block, rb_cProc); 569 } 570 return block->proc; 571} 572 573VALUE 574rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass) 575{ 576 VALUE procval, envval, blockprocval = 0; 577 rb_proc_t *proc; 578 rb_control_frame_t *cfp = RUBY_VM_GET_CFP_FROM_BLOCK_PTR(block); 579 580 if (block->proc) { 581 rb_bug("rb_vm_make_proc: Proc value is already created."); 582 } 583 584 envval = vm_make_env_object(th, cfp, &blockprocval); 585 586 if (PROCDEBUG) { 587 check_env_value(envval); 588 } 589 procval = rb_proc_alloc(klass); 590 GetProcPtr(procval, proc); 591 proc->blockprocval = blockprocval; 592 proc->block.self = block->self; 593 proc->block.klass = block->klass; 594 proc->block.ep = block->ep; 595 proc->block.iseq = block->iseq; 596 proc->block.proc = procval; 597 proc->envval = envval; 598 proc->safe_level = th->safe_level; 599 600 if (VMDEBUG) { 601 if (th->stack < block->ep && block->ep < th->stack + th->stack_size) { 602 rb_bug("invalid ptr: block->ep"); 603 } 604 } 605 606 return procval; 607} 608 609/* C -> Ruby: block */ 610 611static inline VALUE 612invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, 613 VALUE self, int argc, const VALUE *argv, 614 const rb_block_t *blockptr, const NODE *cref, 615 VALUE defined_class) 616{ 617 if (SPECIAL_CONST_P(block->iseq)) 618 return Qnil; 619 else if (BUILTIN_TYPE(block->iseq) != T_NODE) { 620 const rb_iseq_t *iseq = block->iseq; 621 const rb_control_frame_t *cfp; 622 int i, opt_pc, arg_size = iseq->arg_size; 623 int type = block_proc_is_lambda(block->proc) ? 624 VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; 625 626 cfp = th->cfp; 627 CHECK_VM_STACK_OVERFLOW(cfp, argc + iseq->stack_max); 628 629 for (i=0; i<argc; i++) { 630 cfp->sp[i] = argv[i]; 631 } 632 633 opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr, 634 type == VM_FRAME_MAGIC_LAMBDA); 635 636 vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, 637 self, defined_class, 638 VM_ENVVAL_PREV_EP_PTR(block->ep), 639 iseq->iseq_encoded + opt_pc, 640 cfp->sp + arg_size, iseq->local_size - arg_size, 641 th->passed_me); 642 th->passed_me = 0; 643 644 if (cref) { 645 th->cfp->ep[-1] = (VALUE)cref; 646 } 647 648 return vm_exec(th); 649 } 650 else { 651 return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr); 652 } 653} 654 655static inline const rb_block_t * 656check_block(rb_thread_t *th) 657{ 658 const rb_block_t *blockptr = VM_CF_BLOCK_PTR(th->cfp); 659 660 if (blockptr == 0) { 661 rb_vm_localjump_error("no block given", Qnil, 0); 662 } 663 664 return blockptr; 665} 666 667static inline VALUE 668vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref) 669{ 670 const rb_block_t *blockptr = check_block(th); 671 return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref, 672 blockptr->klass); 673} 674 675static inline VALUE 676vm_yield(rb_thread_t *th, int argc, const VALUE *argv) 677{ 678 const rb_block_t *blockptr = check_block(th); 679 return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0, 680 blockptr->klass); 681} 682 683static VALUE 684vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, 685 int argc, const VALUE *argv, const rb_block_t *blockptr) 686{ 687 VALUE val = Qundef; 688 int state; 689 volatile int stored_safe = th->safe_level; 690 691 TH_PUSH_TAG(th); 692 if ((state = EXEC_TAG()) == 0) { 693 if (!proc->is_from_method) { 694 th->safe_level = proc->safe_level; 695 } 696 val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, 697 defined_class); 698 } 699 TH_POP_TAG(); 700 701 if (!proc->is_from_method) { 702 th->safe_level = stored_safe; 703 } 704 705 if (state) { 706 JUMP_TAG(state); 707 } 708 return val; 709} 710 711VALUE 712rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, 713 int argc, const VALUE *argv, const rb_block_t *blockptr) 714{ 715 return vm_invoke_proc(th, proc, proc->block.self, proc->block.klass, 716 argc, argv, blockptr); 717} 718 719/* special variable */ 720 721static rb_control_frame_t * 722vm_normal_frame(rb_thread_t *th, rb_control_frame_t *cfp) 723{ 724 while (cfp->pc == 0) { 725 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 726 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { 727 return 0; 728 } 729 } 730 return cfp; 731} 732 733static VALUE 734vm_cfp_svar_get(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key) 735{ 736 cfp = vm_normal_frame(th, cfp); 737 return lep_svar_get(th, cfp ? VM_CF_LEP(cfp) : 0, key); 738} 739 740static void 741vm_cfp_svar_set(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key, const VALUE val) 742{ 743 cfp = vm_normal_frame(th, cfp); 744 lep_svar_set(th, cfp ? VM_CF_LEP(cfp) : 0, key, val); 745} 746 747static VALUE 748vm_svar_get(VALUE key) 749{ 750 rb_thread_t *th = GET_THREAD(); 751 return vm_cfp_svar_get(th, th->cfp, key); 752} 753 754static void 755vm_svar_set(VALUE key, VALUE val) 756{ 757 rb_thread_t *th = GET_THREAD(); 758 vm_cfp_svar_set(th, th->cfp, key, val); 759} 760 761VALUE 762rb_backref_get(void) 763{ 764 return vm_svar_get(1); 765} 766 767void 768rb_backref_set(VALUE val) 769{ 770 vm_svar_set(1, val); 771} 772 773VALUE 774rb_lastline_get(void) 775{ 776 return vm_svar_get(0); 777} 778 779void 780rb_lastline_set(VALUE val) 781{ 782 vm_svar_set(0, val); 783} 784 785/* misc */ 786 787VALUE 788rb_sourcefilename(void) 789{ 790 rb_thread_t *th = GET_THREAD(); 791 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 792 793 if (cfp) { 794 return cfp->iseq->location.path; 795 } 796 else { 797 return Qnil; 798 } 799} 800 801const char * 802rb_sourcefile(void) 803{ 804 rb_thread_t *th = GET_THREAD(); 805 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 806 807 if (cfp) { 808 return RSTRING_PTR(cfp->iseq->location.path); 809 } 810 else { 811 return 0; 812 } 813} 814 815int 816rb_sourceline(void) 817{ 818 rb_thread_t *th = GET_THREAD(); 819 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 820 821 if (cfp) { 822 return rb_vm_get_sourceline(cfp); 823 } 824 else { 825 return 0; 826 } 827} 828 829NODE * 830rb_vm_cref(void) 831{ 832 rb_thread_t *th = GET_THREAD(); 833 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 834 835 if (cfp == 0) { 836 return NULL; 837 } 838 return rb_vm_get_cref(cfp->iseq, cfp->ep); 839} 840 841#if 0 842void 843debug_cref(NODE *cref) 844{ 845 while (cref) { 846 dp(cref->nd_clss); 847 printf("%ld\n", cref->nd_visi); 848 cref = cref->nd_next; 849 } 850} 851#endif 852 853VALUE 854rb_vm_cbase(void) 855{ 856 rb_thread_t *th = GET_THREAD(); 857 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 858 859 if (cfp == 0) { 860 rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread"); 861 } 862 return vm_get_cbase(cfp->iseq, cfp->ep); 863} 864 865/* jump */ 866 867static VALUE 868make_localjump_error(const char *mesg, VALUE value, int reason) 869{ 870 extern VALUE rb_eLocalJumpError; 871 VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg); 872 ID id; 873 874 switch (reason) { 875 case TAG_BREAK: 876 CONST_ID(id, "break"); 877 break; 878 case TAG_REDO: 879 CONST_ID(id, "redo"); 880 break; 881 case TAG_RETRY: 882 CONST_ID(id, "retry"); 883 break; 884 case TAG_NEXT: 885 CONST_ID(id, "next"); 886 break; 887 case TAG_RETURN: 888 CONST_ID(id, "return"); 889 break; 890 default: 891 CONST_ID(id, "noreason"); 892 break; 893 } 894 rb_iv_set(exc, "@exit_value", value); 895 rb_iv_set(exc, "@reason", ID2SYM(id)); 896 return exc; 897} 898 899void 900rb_vm_localjump_error(const char *mesg, VALUE value, int reason) 901{ 902 VALUE exc = make_localjump_error(mesg, value, reason); 903 rb_exc_raise(exc); 904} 905 906VALUE 907rb_vm_make_jump_tag_but_local_jump(int state, VALUE val) 908{ 909 VALUE result = Qnil; 910 911 if (val == Qundef) { 912 val = GET_THREAD()->tag->retval; 913 } 914 switch (state) { 915 case 0: 916 break; 917 case TAG_RETURN: 918 result = make_localjump_error("unexpected return", val, state); 919 break; 920 case TAG_BREAK: 921 result = make_localjump_error("unexpected break", val, state); 922 break; 923 case TAG_NEXT: 924 result = make_localjump_error("unexpected next", val, state); 925 break; 926 case TAG_REDO: 927 result = make_localjump_error("unexpected redo", Qnil, state); 928 break; 929 case TAG_RETRY: 930 result = make_localjump_error("retry outside of rescue clause", Qnil, state); 931 break; 932 default: 933 break; 934 } 935 return result; 936} 937 938void 939rb_vm_jump_tag_but_local_jump(int state) 940{ 941 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef); 942 if (!NIL_P(exc)) rb_exc_raise(exc); 943 JUMP_TAG(state); 944} 945 946NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val)); 947 948static void 949vm_iter_break(rb_thread_t *th, VALUE val) 950{ 951 rb_control_frame_t *cfp = th->cfp; 952 VALUE *ep = VM_CF_PREV_EP(cfp); 953 954 th->state = TAG_BREAK; 955 th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)ep, TAG_BREAK); 956 TH_JUMP_TAG(th, TAG_BREAK); 957} 958 959void 960rb_iter_break(void) 961{ 962 vm_iter_break(GET_THREAD(), Qnil); 963} 964 965void 966rb_iter_break_value(VALUE val) 967{ 968 vm_iter_break(GET_THREAD(), val); 969} 970 971/* optimization: redefine management */ 972 973static st_table *vm_opt_method_table = 0; 974 975static int 976vm_redefinition_check_flag(VALUE klass) 977{ 978 if (klass == rb_cFixnum) return FIXNUM_REDEFINED_OP_FLAG; 979 if (klass == rb_cFloat) return FLOAT_REDEFINED_OP_FLAG; 980 if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG; 981 if (klass == rb_cArray) return ARRAY_REDEFINED_OP_FLAG; 982 if (klass == rb_cHash) return HASH_REDEFINED_OP_FLAG; 983 if (klass == rb_cBignum) return BIGNUM_REDEFINED_OP_FLAG; 984 if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG; 985 if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG; 986 return 0; 987} 988 989static void 990rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass) 991{ 992 st_data_t bop; 993 if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) { 994 if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) { 995 int flag = vm_redefinition_check_flag(klass); 996 997 ruby_vm_redefined_flag[bop] |= flag; 998 } 999 } 1000} 1001 1002static int 1003check_redefined_method(st_data_t key, st_data_t value, st_data_t data) 1004{ 1005 ID mid = (ID)key; 1006 rb_method_entry_t *me = (rb_method_entry_t *)value; 1007 VALUE klass = (VALUE)data; 1008 rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL); 1009 1010 if (newme != me) 1011 rb_vm_check_redefinition_opt_method(me, me->klass); 1012 return ST_CONTINUE; 1013} 1014 1015void 1016rb_vm_check_redefinition_by_prepend(VALUE klass) 1017{ 1018 if (!vm_redefinition_check_flag(klass)) return; 1019 st_foreach(RCLASS_M_TBL(RCLASS_ORIGIN(klass)), check_redefined_method, 1020 (st_data_t)klass); 1021} 1022 1023static void 1024add_opt_method(VALUE klass, ID mid, VALUE bop) 1025{ 1026 rb_method_entry_t *me; 1027 if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) && me->def && 1028 me->def->type == VM_METHOD_TYPE_CFUNC) { 1029 st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop); 1030 } 1031 else { 1032 rb_bug("undefined optimized method: %s", rb_id2name(mid)); 1033 } 1034} 1035 1036static void 1037vm_init_redefined_flag(void) 1038{ 1039 ID mid; 1040 VALUE bop; 1041 1042 vm_opt_method_table = st_init_numtable(); 1043 1044#define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0) 1045#define C(k) add_opt_method(rb_c##k, mid, bop) 1046 OP(PLUS, PLUS), (C(Fixnum), C(Float), C(String), C(Array)); 1047 OP(MINUS, MINUS), (C(Fixnum), C(Float)); 1048 OP(MULT, MULT), (C(Fixnum), C(Float)); 1049 OP(DIV, DIV), (C(Fixnum), C(Float)); 1050 OP(MOD, MOD), (C(Fixnum), C(Float)); 1051 OP(Eq, EQ), (C(Fixnum), C(Float), C(String)); 1052 OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String)); 1053 OP(LT, LT), (C(Fixnum), C(Float)); 1054 OP(LE, LE), (C(Fixnum), C(Float)); 1055 OP(GT, GT), (C(Fixnum), C(Float)); 1056 OP(GE, GE), (C(Fixnum), C(Float)); 1057 OP(LTLT, LTLT), (C(String), C(Array)); 1058 OP(AREF, AREF), (C(Array), C(Hash)); 1059 OP(ASET, ASET), (C(Array), C(Hash)); 1060 OP(Length, LENGTH), (C(Array), C(String), C(Hash)); 1061 OP(Size, SIZE), (C(Array), C(String), C(Hash)); 1062 OP(EmptyP, EMPTY_P), (C(Array), C(String), C(Hash)); 1063 OP(Succ, SUCC), (C(Fixnum), C(String), C(Time)); 1064#undef C 1065#undef OP 1066} 1067 1068/* for vm development */ 1069 1070#if VMDEBUG 1071static const char * 1072vm_frametype_name(const rb_control_frame_t *cfp) 1073{ 1074 switch (VM_FRAME_TYPE(cfp)) { 1075 case VM_FRAME_MAGIC_METHOD: return "method"; 1076 case VM_FRAME_MAGIC_BLOCK: return "block"; 1077 case VM_FRAME_MAGIC_CLASS: return "class"; 1078 case VM_FRAME_MAGIC_TOP: return "top"; 1079 case VM_FRAME_MAGIC_CFUNC: return "cfunc"; 1080 case VM_FRAME_MAGIC_PROC: return "proc"; 1081 case VM_FRAME_MAGIC_IFUNC: return "ifunc"; 1082 case VM_FRAME_MAGIC_EVAL: return "eval"; 1083 case VM_FRAME_MAGIC_LAMBDA: return "lambda"; 1084 default: 1085 rb_bug("unknown frame"); 1086 } 1087} 1088#endif 1089 1090/* evaluator body */ 1091 1092/* finish 1093 VMe (h1) finish 1094 VM finish F1 F2 1095 cfunc finish F1 F2 C1 1096 rb_funcall finish F1 F2 C1 1097 VMe finish F1 F2 C1 1098 VM finish F1 F2 C1 F3 1099 1100 F1 - F3 : pushed by VM 1101 C1 : pushed by send insn (CFUNC) 1102 1103 struct CONTROL_FRAME { 1104 VALUE *pc; // cfp[0], program counter 1105 VALUE *sp; // cfp[1], stack pointer 1106 VALUE *bp; // cfp[2], base pointer 1107 rb_iseq_t *iseq; // cfp[3], iseq 1108 VALUE flag; // cfp[4], magic 1109 VALUE self; // cfp[5], self 1110 VALUE *ep; // cfp[6], env pointer 1111 rb_iseq_t * block_iseq; // cfp[7], block iseq 1112 VALUE proc; // cfp[8], always 0 1113 }; 1114 1115 struct BLOCK { 1116 VALUE self; 1117 VALUE *ep; 1118 rb_iseq_t *block_iseq; 1119 VALUE proc; 1120 }; 1121 1122 struct METHOD_CONTROL_FRAME { 1123 rb_control_frame_t frame; 1124 }; 1125 1126 struct METHOD_FRAME { 1127 VALUE arg0; 1128 ... 1129 VALUE argM; 1130 VALUE param0; 1131 ... 1132 VALUE paramN; 1133 VALUE cref; 1134 VALUE special; // lep [1] 1135 struct block_object *block_ptr | 0x01; // lep [0] 1136 }; 1137 1138 struct BLOCK_CONTROL_FRAME { 1139 rb_control_frame_t frame; 1140 }; 1141 1142 struct BLOCK_FRAME { 1143 VALUE arg0; 1144 ... 1145 VALUE argM; 1146 VALUE param0; 1147 ... 1148 VALUE paramN; 1149 VALUE cref; 1150 VALUE *(prev_ptr | 0x01); // ep[0] 1151 }; 1152 1153 struct CLASS_CONTROL_FRAME { 1154 rb_control_frame_t frame; 1155 }; 1156 1157 struct CLASS_FRAME { 1158 VALUE param0; 1159 ... 1160 VALUE paramN; 1161 VALUE cref; 1162 VALUE prev_ep; // for frame jump 1163 }; 1164 1165 struct C_METHOD_CONTROL_FRAME { 1166 VALUE *pc; // 0 1167 VALUE *sp; // stack pointer 1168 VALUE *bp; // base pointer (used in exception) 1169 rb_iseq_t *iseq; // cmi 1170 VALUE magic; // C_METHOD_FRAME 1171 VALUE self; // ? 1172 VALUE *ep; // ep == lep 1173 rb_iseq_t * block_iseq; // 1174 VALUE proc; // always 0 1175 }; 1176 1177 struct C_BLOCK_CONTROL_FRAME { 1178 VALUE *pc; // point only "finish" insn 1179 VALUE *sp; // sp 1180 rb_iseq_t *iseq; // ? 1181 VALUE magic; // C_METHOD_FRAME 1182 VALUE self; // needed? 1183 VALUE *ep; // ep 1184 rb_iseq_t * block_iseq; // 0 1185 }; 1186 */ 1187 1188 1189static VALUE 1190vm_exec(rb_thread_t *th) 1191{ 1192 int state; 1193 VALUE result, err; 1194 VALUE initial = 0; 1195 VALUE *escape_ep = NULL; 1196 1197 TH_PUSH_TAG(th); 1198 _tag.retval = Qnil; 1199 if ((state = EXEC_TAG()) == 0) { 1200 vm_loop_start: 1201 result = vm_exec_core(th, initial); 1202 if ((state = th->state) != 0) { 1203 err = result; 1204 th->state = 0; 1205 goto exception_handler; 1206 } 1207 } 1208 else { 1209 int i; 1210 struct iseq_catch_table_entry *entry; 1211 unsigned long epc, cont_pc, cont_sp; 1212 VALUE catch_iseqval; 1213 rb_control_frame_t *cfp; 1214 VALUE type; 1215 1216 err = th->errinfo; 1217 1218 exception_handler: 1219 cont_pc = cont_sp = catch_iseqval = 0; 1220 1221 while (th->cfp->pc == 0 || th->cfp->iseq == 0) { 1222 if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) { 1223 const rb_method_entry_t *me = th->cfp->me; 1224 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); 1225 RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id); 1226 } 1227 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); 1228 } 1229 1230 cfp = th->cfp; 1231 epc = cfp->pc - cfp->iseq->iseq_encoded; 1232 1233 if (state == TAG_BREAK || state == TAG_RETURN) { 1234 escape_ep = GET_THROWOBJ_CATCH_POINT(err); 1235 1236 if (cfp->ep == escape_ep) { 1237 if (state == TAG_RETURN) { 1238 if (!VM_FRAME_TYPE_FINISH_P(cfp)) { 1239 SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->ep); 1240 SET_THROWOBJ_STATE(err, state = TAG_BREAK); 1241 } 1242 else { 1243 for (i = 0; i < cfp->iseq->catch_table_size; i++) { 1244 entry = &cfp->iseq->catch_table[i]; 1245 if (entry->start < epc && entry->end >= epc) { 1246 if (entry->type == CATCH_TYPE_ENSURE) { 1247 catch_iseqval = entry->iseq; 1248 cont_pc = entry->cont; 1249 cont_sp = entry->sp; 1250 break; 1251 } 1252 } 1253 } 1254 if (!catch_iseqval) { 1255 result = GET_THROWOBJ_VAL(err); 1256 th->errinfo = Qnil; 1257 vm_pop_frame(th); 1258 goto finish_vme; 1259 } 1260 } 1261 /* through */ 1262 } 1263 else { 1264 /* TAG_BREAK */ 1265#if OPT_STACK_CACHING 1266 initial = (GET_THROWOBJ_VAL(err)); 1267#else 1268 *th->cfp->sp++ = (GET_THROWOBJ_VAL(err)); 1269#endif 1270 th->errinfo = Qnil; 1271 goto vm_loop_start; 1272 } 1273 } 1274 } 1275 1276 if (state == TAG_RAISE) { 1277 for (i = 0; i < cfp->iseq->catch_table_size; i++) { 1278 entry = &cfp->iseq->catch_table[i]; 1279 if (entry->start < epc && entry->end >= epc) { 1280 1281 if (entry->type == CATCH_TYPE_RESCUE || 1282 entry->type == CATCH_TYPE_ENSURE) { 1283 catch_iseqval = entry->iseq; 1284 cont_pc = entry->cont; 1285 cont_sp = entry->sp; 1286 break; 1287 } 1288 } 1289 } 1290 } 1291 else if (state == TAG_RETRY) { 1292 for (i = 0; i < cfp->iseq->catch_table_size; i++) { 1293 entry = &cfp->iseq->catch_table[i]; 1294 if (entry->start < epc && entry->end >= epc) { 1295 1296 if (entry->type == CATCH_TYPE_ENSURE) { 1297 catch_iseqval = entry->iseq; 1298 cont_pc = entry->cont; 1299 cont_sp = entry->sp; 1300 break; 1301 } 1302 else if (entry->type == CATCH_TYPE_RETRY) { 1303 VALUE *escape_ep; 1304 escape_ep = GET_THROWOBJ_CATCH_POINT(err); 1305 if (cfp->ep == escape_ep) { 1306 cfp->pc = cfp->iseq->iseq_encoded + entry->cont; 1307 th->errinfo = Qnil; 1308 goto vm_loop_start; 1309 } 1310 } 1311 } 1312 } 1313 } 1314 else if (state == TAG_BREAK && ((VALUE)escape_ep & ~0x03) == 0) { 1315 type = CATCH_TYPE_BREAK; 1316 1317 search_restart_point: 1318 for (i = 0; i < cfp->iseq->catch_table_size; i++) { 1319 entry = &cfp->iseq->catch_table[i]; 1320 1321 if (entry->start < epc && entry->end >= epc) { 1322 if (entry->type == CATCH_TYPE_ENSURE) { 1323 catch_iseqval = entry->iseq; 1324 cont_pc = entry->cont; 1325 cont_sp = entry->sp; 1326 break; 1327 } 1328 else if (entry->type == type) { 1329 cfp->pc = cfp->iseq->iseq_encoded + entry->cont; 1330 cfp->sp = vm_base_ptr(cfp) + entry->sp; 1331 1332 if (state != TAG_REDO) { 1333#if OPT_STACK_CACHING 1334 initial = (GET_THROWOBJ_VAL(err)); 1335#else 1336 *th->cfp->sp++ = (GET_THROWOBJ_VAL(err)); 1337#endif 1338 } 1339 th->errinfo = Qnil; 1340 th->state = 0; 1341 goto vm_loop_start; 1342 } 1343 } 1344 } 1345 } 1346 else if (state == TAG_REDO) { 1347 type = CATCH_TYPE_REDO; 1348 goto search_restart_point; 1349 } 1350 else if (state == TAG_NEXT) { 1351 type = CATCH_TYPE_NEXT; 1352 goto search_restart_point; 1353 } 1354 else { 1355 for (i = 0; i < cfp->iseq->catch_table_size; i++) { 1356 entry = &cfp->iseq->catch_table[i]; 1357 if (entry->start < epc && entry->end >= epc) { 1358 1359 if (entry->type == CATCH_TYPE_ENSURE) { 1360 catch_iseqval = entry->iseq; 1361 cont_pc = entry->cont; 1362 cont_sp = entry->sp; 1363 break; 1364 } 1365 } 1366 } 1367 } 1368 1369 if (catch_iseqval != 0) { 1370 /* found catch table */ 1371 rb_iseq_t *catch_iseq; 1372 1373 /* enter catch scope */ 1374 GetISeqPtr(catch_iseqval, catch_iseq); 1375 cfp->sp = vm_base_ptr(cfp) + cont_sp; 1376 cfp->pc = cfp->iseq->iseq_encoded + cont_pc; 1377 1378 /* push block frame */ 1379 cfp->sp[0] = err; 1380 vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK, 1381 cfp->self, cfp->klass, 1382 VM_ENVVAL_PREV_EP_PTR(cfp->ep), 1383 catch_iseq->iseq_encoded, 1384 cfp->sp + 1 /* push value */, 1385 catch_iseq->local_size - 1, 1386 cfp->me); 1387 1388 state = 0; 1389 th->state = 0; 1390 th->errinfo = Qnil; 1391 goto vm_loop_start; 1392 } 1393 else { 1394 /* skip frame */ 1395 1396 switch (VM_FRAME_TYPE(th->cfp)) { 1397 case VM_FRAME_MAGIC_METHOD: 1398 RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0); 1399 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil); 1400 break; 1401 case VM_FRAME_MAGIC_BLOCK: 1402 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); 1403 break; 1404 case VM_FRAME_MAGIC_CLASS: 1405 EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil); 1406 break; 1407 } 1408 1409 if (VM_FRAME_TYPE_FINISH_P(th->cfp)) { 1410 vm_pop_frame(th); 1411 th->errinfo = err; 1412 TH_POP_TAG2(); 1413 JUMP_TAG(state); 1414 } 1415 else { 1416 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); 1417 goto exception_handler; 1418 } 1419 } 1420 } 1421 finish_vme: 1422 TH_POP_TAG(); 1423 return result; 1424} 1425 1426/* misc */ 1427 1428VALUE 1429rb_iseq_eval(VALUE iseqval) 1430{ 1431 rb_thread_t *th = GET_THREAD(); 1432 VALUE val; 1433 1434 vm_set_top_stack(th, iseqval); 1435 1436 val = vm_exec(th); 1437 RB_GC_GUARD(iseqval); /* prohibit tail call optimization */ 1438 return val; 1439} 1440 1441VALUE 1442rb_iseq_eval_main(VALUE iseqval) 1443{ 1444 rb_thread_t *th = GET_THREAD(); 1445 VALUE val; 1446 1447 vm_set_main_stack(th, iseqval); 1448 1449 val = vm_exec(th); 1450 RB_GC_GUARD(iseqval); /* prohibit tail call optimization */ 1451 return val; 1452} 1453 1454int 1455rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp) 1456{ 1457 rb_iseq_t *iseq = cfp->iseq; 1458 if (!iseq && cfp->me) { 1459 if (idp) *idp = cfp->me->def->original_id; 1460 if (klassp) *klassp = cfp->me->klass; 1461 return 1; 1462 } 1463 while (iseq) { 1464 if (RUBY_VM_IFUNC_P(iseq)) { 1465 if (idp) CONST_ID(*idp, "<ifunc>"); 1466 if (klassp) *klassp = 0; 1467 return 1; 1468 } 1469 if (iseq->defined_method_id) { 1470 if (idp) *idp = iseq->defined_method_id; 1471 if (klassp) *klassp = iseq->klass; 1472 return 1; 1473 } 1474 if (iseq->local_iseq == iseq) { 1475 break; 1476 } 1477 iseq = iseq->parent_iseq; 1478 } 1479 return 0; 1480} 1481 1482int 1483rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp) 1484{ 1485 return rb_vm_control_frame_id_and_class(th->cfp, idp, klassp); 1486} 1487 1488int 1489rb_frame_method_id_and_class(ID *idp, VALUE *klassp) 1490{ 1491 return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp); 1492} 1493 1494VALUE 1495rb_thread_current_status(const rb_thread_t *th) 1496{ 1497 const rb_control_frame_t *cfp = th->cfp; 1498 VALUE str = Qnil; 1499 1500 if (cfp->iseq != 0) { 1501 if (cfp->pc != 0) { 1502 rb_iseq_t *iseq = cfp->iseq; 1503 int line_no = rb_vm_get_sourceline(cfp); 1504 char *file = RSTRING_PTR(iseq->location.path); 1505 str = rb_sprintf("%s:%d:in `%s'", 1506 file, line_no, RSTRING_PTR(iseq->location.label)); 1507 } 1508 } 1509 else if (cfp->me->def->original_id) { 1510 str = rb_sprintf("`%s#%s' (cfunc)", 1511 rb_class2name(cfp->me->klass), 1512 rb_id2name(cfp->me->def->original_id)); 1513 } 1514 1515 return str; 1516} 1517 1518VALUE 1519rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, 1520 const rb_block_t *blockptr, VALUE filename) 1521{ 1522 rb_thread_t *th = GET_THREAD(); 1523 const rb_control_frame_t *reg_cfp = th->cfp; 1524 volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP); 1525 VALUE val; 1526 1527 vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, 1528 recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0); 1529 1530 val = (*func)(arg); 1531 1532 vm_pop_frame(th); 1533 return val; 1534} 1535 1536/* vm */ 1537 1538static int 1539vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy) 1540{ 1541 VALUE thval = (VALUE)key; 1542 rb_gc_mark(thval); 1543 return ST_CONTINUE; 1544} 1545 1546void vm_trace_mark_event_hooks(rb_hook_list_t *hooks); 1547 1548void 1549rb_vm_mark(void *ptr) 1550{ 1551 int i; 1552 1553 RUBY_MARK_ENTER("vm"); 1554 RUBY_GC_INFO("-------------------------------------------------\n"); 1555 if (ptr) { 1556 rb_vm_t *vm = ptr; 1557 if (vm->living_threads) { 1558 st_foreach(vm->living_threads, vm_mark_each_thread_func, 0); 1559 } 1560 RUBY_MARK_UNLESS_NULL(vm->thgroup_default); 1561 RUBY_MARK_UNLESS_NULL(vm->mark_object_ary); 1562 RUBY_MARK_UNLESS_NULL(vm->load_path); 1563 RUBY_MARK_UNLESS_NULL(vm->load_path_snapshot); 1564 RUBY_MARK_UNLESS_NULL(vm->load_path_check_cache); 1565 RUBY_MARK_UNLESS_NULL(vm->expanded_load_path); 1566 RUBY_MARK_UNLESS_NULL(vm->loaded_features); 1567 RUBY_MARK_UNLESS_NULL(vm->loaded_features_snapshot); 1568 RUBY_MARK_UNLESS_NULL(vm->top_self); 1569 RUBY_MARK_UNLESS_NULL(vm->coverages); 1570 rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count); 1571 1572 if (vm->loading_table) { 1573 rb_mark_tbl(vm->loading_table); 1574 } 1575 if (vm->loaded_features_index) { 1576 rb_mark_tbl(vm->loaded_features_index); 1577 } 1578 1579 vm_trace_mark_event_hooks(&vm->event_hooks); 1580 1581 for (i = 0; i < RUBY_NSIG; i++) { 1582 if (vm->trap_list[i].cmd) 1583 rb_gc_mark(vm->trap_list[i].cmd); 1584 } 1585 if (vm->defined_strings) { 1586 rb_gc_mark_locations(vm->defined_strings, vm->defined_strings + DEFINED_EXPR); 1587 } 1588 } 1589 1590 RUBY_MARK_LEAVE("vm"); 1591} 1592 1593#define vm_free 0 1594 1595int 1596ruby_vm_destruct(rb_vm_t *vm) 1597{ 1598 RUBY_FREE_ENTER("vm"); 1599 if (vm) { 1600 rb_thread_t *th = vm->main_thread; 1601#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE 1602 struct rb_objspace *objspace = vm->objspace; 1603#endif 1604 rb_gc_force_recycle(vm->self); 1605 vm->main_thread = 0; 1606 if (th) { 1607 rb_fiber_reset_root_local_storage(th->self); 1608 thread_free(th); 1609 } 1610 if (vm->living_threads) { 1611 st_free_table(vm->living_threads); 1612 vm->living_threads = 0; 1613 } 1614#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE 1615 if (objspace) { 1616 rb_objspace_free(objspace); 1617 } 1618#endif 1619 ruby_vm_run_at_exit_hooks(vm); 1620 rb_vm_gvl_destroy(vm); 1621 ruby_xfree(vm); 1622 ruby_current_vm = 0; 1623 } 1624 RUBY_FREE_LEAVE("vm"); 1625 return 0; 1626} 1627 1628static size_t 1629vm_memsize(const void *ptr) 1630{ 1631 if (ptr) { 1632 const rb_vm_t *vmobj = ptr; 1633 size_t size = sizeof(rb_vm_t); 1634 size += st_memsize(vmobj->living_threads); 1635 if (vmobj->defined_strings) { 1636 size += DEFINED_EXPR * sizeof(VALUE); 1637 } 1638 return size; 1639 } 1640 else { 1641 return 0; 1642 } 1643} 1644 1645static const rb_data_type_t vm_data_type = { 1646 "VM", 1647 {rb_vm_mark, vm_free, vm_memsize,}, 1648}; 1649 1650 1651static VALUE 1652vm_default_params(void) 1653{ 1654 rb_vm_t *vm = GET_VM(); 1655 VALUE result = rb_hash_new(); 1656#define SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), SIZET2NUM(vm->default_params.name)); 1657 SET(thread_vm_stack_size); 1658 SET(thread_machine_stack_size); 1659 SET(fiber_vm_stack_size); 1660 SET(fiber_machine_stack_size); 1661#undef SET 1662 rb_obj_freeze(result); 1663 return result; 1664} 1665 1666static size_t 1667get_param(const char *name, size_t default_value, size_t min_value) 1668{ 1669 const char *envval; 1670 size_t result = default_value; 1671 if ((envval = getenv(name)) != 0) { 1672 long val = atol(envval); 1673 if (val < (long)min_value) { 1674 val = (long)min_value; 1675 } 1676 result = (size_t)(((val -1 + RUBY_VM_SIZE_ALIGN) / RUBY_VM_SIZE_ALIGN) * RUBY_VM_SIZE_ALIGN); 1677 } 1678 if (0) fprintf(stderr, "%s: %"PRIdSIZE"\n", name, result); /* debug print */ 1679 1680 return result; 1681} 1682 1683static void 1684check_machine_stack_size(size_t *sizep) 1685{ 1686#ifdef PTHREAD_STACK_MIN 1687 size_t size = *sizep; 1688#endif 1689 1690#ifdef __SYMBIAN32__ 1691 *sizep = 64 * 1024; /* 64KB: Let's be slightly more frugal on mobile platform */ 1692#endif 1693 1694#ifdef PTHREAD_STACK_MIN 1695 if (size < PTHREAD_STACK_MIN) { 1696 *sizep = PTHREAD_STACK_MIN * 2; 1697 } 1698#endif 1699} 1700 1701static void 1702vm_default_params_setup(rb_vm_t *vm) 1703{ 1704 vm->default_params.thread_vm_stack_size = 1705 get_param("RUBY_THREAD_VM_STACK_SIZE", 1706 RUBY_VM_THREAD_VM_STACK_SIZE, 1707 RUBY_VM_THREAD_VM_STACK_SIZE_MIN); 1708 1709 vm->default_params.thread_machine_stack_size = 1710 get_param("RUBY_THREAD_MACHINE_STACK_SIZE", 1711 RUBY_VM_THREAD_MACHINE_STACK_SIZE, 1712 RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN); 1713 1714 vm->default_params.fiber_vm_stack_size = 1715 get_param("RUBY_FIBER_VM_STACK_SIZE", 1716 RUBY_VM_FIBER_VM_STACK_SIZE, 1717 RUBY_VM_FIBER_VM_STACK_SIZE_MIN); 1718 1719 vm->default_params.fiber_machine_stack_size = 1720 get_param("RUBY_FIBER_MACHINE_STACK_SIZE", 1721 RUBY_VM_FIBER_MACHINE_STACK_SIZE, 1722 RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN); 1723 1724 /* environment dependent check */ 1725 check_machine_stack_size(&vm->default_params.thread_machine_stack_size); 1726 check_machine_stack_size(&vm->default_params.fiber_machine_stack_size); 1727} 1728 1729static void 1730vm_init2(rb_vm_t *vm) 1731{ 1732 MEMZERO(vm, rb_vm_t, 1); 1733 vm->src_encoding_index = -1; 1734 vm->at_exit.basic.flags = (T_ARRAY | RARRAY_EMBED_FLAG) & ~RARRAY_EMBED_LEN_MASK; /* len set 0 */ 1735 vm->at_exit.basic.klass = 0; 1736 1737 vm_default_params_setup(vm); 1738} 1739 1740/* Thread */ 1741 1742#define USE_THREAD_DATA_RECYCLE 1 1743 1744#if USE_THREAD_DATA_RECYCLE 1745#define RECYCLE_MAX 64 1746static VALUE *thread_recycle_stack_slot[RECYCLE_MAX]; 1747static int thread_recycle_stack_count = 0; 1748 1749static VALUE * 1750thread_recycle_stack(size_t size) 1751{ 1752 if (thread_recycle_stack_count) { 1753 /* TODO: check stack size if stack sizes are variable */ 1754 return thread_recycle_stack_slot[--thread_recycle_stack_count]; 1755 } 1756 else { 1757 return ALLOC_N(VALUE, size); 1758 } 1759} 1760 1761#else 1762#define thread_recycle_stack(size) ALLOC_N(VALUE, (size)) 1763#endif 1764 1765void 1766rb_thread_recycle_stack_release(VALUE *stack) 1767{ 1768#if USE_THREAD_DATA_RECYCLE 1769 if (thread_recycle_stack_count < RECYCLE_MAX) { 1770 thread_recycle_stack_slot[thread_recycle_stack_count++] = stack; 1771 return; 1772 } 1773#endif 1774 ruby_xfree(stack); 1775} 1776 1777#ifdef USE_THREAD_RECYCLE 1778static rb_thread_t * 1779thread_recycle_struct(void) 1780{ 1781 void *p = ALLOC_N(rb_thread_t, 1); 1782 memset(p, 0, sizeof(rb_thread_t)); 1783 return p; 1784} 1785#endif 1786 1787void 1788rb_thread_mark(void *ptr) 1789{ 1790 rb_thread_t *th = NULL; 1791 RUBY_MARK_ENTER("thread"); 1792 if (ptr) { 1793 th = ptr; 1794 if (th->stack) { 1795 VALUE *p = th->stack; 1796 VALUE *sp = th->cfp->sp; 1797 rb_control_frame_t *cfp = th->cfp; 1798 rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size); 1799 1800 while (p < sp) { 1801 rb_gc_mark(*p++); 1802 } 1803 rb_gc_mark_locations(p, p + th->mark_stack_len); 1804 1805 while (cfp != limit_cfp) { 1806 rb_iseq_t *iseq = cfp->iseq; 1807 rb_gc_mark(cfp->proc); 1808 rb_gc_mark(cfp->self); 1809 rb_gc_mark(cfp->klass); 1810 if (iseq) { 1811 rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq); 1812 } 1813 if (cfp->me) { 1814 /* TODO: marking `me' can be more sophisticated way */ 1815 ((rb_method_entry_t *)cfp->me)->mark = 1; 1816 rb_mark_method_entry(cfp->me); 1817 } 1818 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 1819 } 1820 } 1821 1822 /* mark ruby objects */ 1823 RUBY_MARK_UNLESS_NULL(th->first_proc); 1824 if (th->first_proc) RUBY_MARK_UNLESS_NULL(th->first_args); 1825 1826 RUBY_MARK_UNLESS_NULL(th->thgroup); 1827 RUBY_MARK_UNLESS_NULL(th->value); 1828 RUBY_MARK_UNLESS_NULL(th->errinfo); 1829 RUBY_MARK_UNLESS_NULL(th->pending_interrupt_queue); 1830 RUBY_MARK_UNLESS_NULL(th->pending_interrupt_mask_stack); 1831 RUBY_MARK_UNLESS_NULL(th->root_svar); 1832 RUBY_MARK_UNLESS_NULL(th->top_self); 1833 RUBY_MARK_UNLESS_NULL(th->top_wrapper); 1834 RUBY_MARK_UNLESS_NULL(th->fiber); 1835 RUBY_MARK_UNLESS_NULL(th->root_fiber); 1836 RUBY_MARK_UNLESS_NULL(th->stat_insn_usage); 1837 RUBY_MARK_UNLESS_NULL(th->last_status); 1838 1839 RUBY_MARK_UNLESS_NULL(th->locking_mutex); 1840 1841 rb_mark_tbl(th->local_storage); 1842 1843 if (GET_THREAD() != th && th->machine_stack_start && th->machine_stack_end) { 1844 rb_gc_mark_machine_stack(th); 1845 rb_gc_mark_locations((VALUE *)&th->machine_regs, 1846 (VALUE *)(&th->machine_regs) + 1847 sizeof(th->machine_regs) / sizeof(VALUE)); 1848 } 1849 1850 vm_trace_mark_event_hooks(&th->event_hooks); 1851 } 1852 1853 RUBY_MARK_LEAVE("thread"); 1854} 1855 1856static void 1857thread_free(void *ptr) 1858{ 1859 rb_thread_t *th; 1860 RUBY_FREE_ENTER("thread"); 1861 1862 if (ptr) { 1863 th = ptr; 1864 1865 if (!th->root_fiber) { 1866 RUBY_FREE_UNLESS_NULL(th->stack); 1867 } 1868 1869 if (th->locking_mutex != Qfalse) { 1870 rb_bug("thread_free: locking_mutex must be NULL (%p:%p)", (void *)th, (void *)th->locking_mutex); 1871 } 1872 if (th->keeping_mutexes != NULL) { 1873 rb_bug("thread_free: keeping_mutexes must be NULL (%p:%p)", (void *)th, (void *)th->keeping_mutexes); 1874 } 1875 1876 if (th->local_storage) { 1877 st_free_table(th->local_storage); 1878 } 1879 1880 if (th->vm && th->vm->main_thread == th) { 1881 RUBY_GC_INFO("main thread\n"); 1882 } 1883 else { 1884#ifdef USE_SIGALTSTACK 1885 if (th->altstack) { 1886 free(th->altstack); 1887 } 1888#endif 1889 ruby_xfree(ptr); 1890 } 1891 if (ruby_current_thread == th) 1892 ruby_current_thread = NULL; 1893 } 1894 RUBY_FREE_LEAVE("thread"); 1895} 1896 1897static size_t 1898thread_memsize(const void *ptr) 1899{ 1900 if (ptr) { 1901 const rb_thread_t *th = ptr; 1902 size_t size = sizeof(rb_thread_t); 1903 1904 if (!th->root_fiber) { 1905 size += th->stack_size * sizeof(VALUE); 1906 } 1907 if (th->local_storage) { 1908 size += st_memsize(th->local_storage); 1909 } 1910 return size; 1911 } 1912 else { 1913 return 0; 1914 } 1915} 1916 1917#define thread_data_type ruby_threadptr_data_type 1918const rb_data_type_t ruby_threadptr_data_type = { 1919 "VM/thread", 1920 { 1921 rb_thread_mark, 1922 thread_free, 1923 thread_memsize, 1924 }, 1925}; 1926 1927VALUE 1928rb_obj_is_thread(VALUE obj) 1929{ 1930 if (rb_typeddata_is_kind_of(obj, &thread_data_type)) { 1931 return Qtrue; 1932 } 1933 else { 1934 return Qfalse; 1935 } 1936} 1937 1938static VALUE 1939thread_alloc(VALUE klass) 1940{ 1941 VALUE volatile obj; 1942#ifdef USE_THREAD_RECYCLE 1943 rb_thread_t *th = thread_recycle_struct(); 1944 obj = TypedData_Wrap_Struct(klass, &thread_data_type, th); 1945#else 1946 rb_thread_t *th; 1947 obj = TypedData_Make_Struct(klass, rb_thread_t, &thread_data_type, th); 1948#endif 1949 return obj; 1950} 1951 1952static void 1953th_init(rb_thread_t *th, VALUE self) 1954{ 1955 th->self = self; 1956 1957 /* allocate thread stack */ 1958#ifdef USE_SIGALTSTACK 1959 /* altstack of main thread is reallocated in another place */ 1960 th->altstack = malloc(rb_sigaltstack_size()); 1961#endif 1962 /* th->stack_size is word number. 1963 * th->vm->default_params.thread_vm_stack_size is byte size. 1964 */ 1965 th->stack_size = th->vm->default_params.thread_vm_stack_size / sizeof(VALUE); 1966 th->stack = thread_recycle_stack(th->stack_size); 1967 1968 th->cfp = (void *)(th->stack + th->stack_size); 1969 1970 vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, 1971 Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0); 1972 1973 th->status = THREAD_RUNNABLE; 1974 th->errinfo = Qnil; 1975 th->last_status = Qnil; 1976 th->waiting_fd = -1; 1977 th->root_svar = Qnil; 1978 1979#if OPT_CALL_THREADED_CODE 1980 th->retval = Qundef; 1981#endif 1982} 1983 1984static VALUE 1985ruby_thread_init(VALUE self) 1986{ 1987 rb_thread_t *th; 1988 rb_vm_t *vm = GET_THREAD()->vm; 1989 GetThreadPtr(self, th); 1990 1991 th->vm = vm; 1992 th_init(th, self); 1993 rb_iv_set(self, "locals", rb_hash_new()); 1994 1995 th->top_wrapper = 0; 1996 th->top_self = rb_vm_top_self(); 1997 th->root_svar = Qnil; 1998 return self; 1999} 2000 2001VALUE 2002rb_thread_alloc(VALUE klass) 2003{ 2004 VALUE self = thread_alloc(klass); 2005 ruby_thread_init(self); 2006 return self; 2007} 2008 2009static void 2010vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, 2011 rb_num_t is_singleton, NODE *cref) 2012{ 2013 VALUE klass = cref->nd_clss; 2014 int noex = (int)cref->nd_visi; 2015 rb_iseq_t *miseq; 2016 GetISeqPtr(iseqval, miseq); 2017 2018 if (miseq->klass) { 2019 RB_GC_GUARD(iseqval) = rb_iseq_clone(iseqval, 0); 2020 GetISeqPtr(iseqval, miseq); 2021 } 2022 2023 if (NIL_P(klass)) { 2024 rb_raise(rb_eTypeError, "no class/module to add method"); 2025 } 2026 2027 if (is_singleton) { 2028 klass = rb_singleton_class(obj); /* class and frozen checked in this API */ 2029 noex = NOEX_PUBLIC; 2030 } 2031 2032 /* dup */ 2033 COPY_CREF(miseq->cref_stack, cref); 2034 miseq->cref_stack->nd_visi = NOEX_PUBLIC; 2035 miseq->klass = klass; 2036 miseq->defined_method_id = id; 2037 rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex); 2038 2039 if (!is_singleton && noex == NOEX_MODFUNC) { 2040 rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC); 2041 } 2042 INC_VM_STATE_VERSION(); 2043} 2044 2045#define REWIND_CFP(expr) do { \ 2046 rb_thread_t *th__ = GET_THREAD(); \ 2047 th__->cfp++; expr; th__->cfp--; \ 2048} while (0) 2049 2050static VALUE 2051m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval) 2052{ 2053 REWIND_CFP({ 2054 vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref()); 2055 }); 2056 return Qnil; 2057} 2058 2059static VALUE 2060m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval) 2061{ 2062 REWIND_CFP({ 2063 vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref()); 2064 }); 2065 return Qnil; 2066} 2067 2068static VALUE 2069m_core_set_method_alias(VALUE self, VALUE cbase, VALUE sym1, VALUE sym2) 2070{ 2071 REWIND_CFP({ 2072 rb_alias(cbase, SYM2ID(sym1), SYM2ID(sym2)); 2073 }); 2074 return Qnil; 2075} 2076 2077static VALUE 2078m_core_set_variable_alias(VALUE self, VALUE sym1, VALUE sym2) 2079{ 2080 REWIND_CFP({ 2081 rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2)); 2082 }); 2083 return Qnil; 2084} 2085 2086static VALUE 2087m_core_undef_method(VALUE self, VALUE cbase, VALUE sym) 2088{ 2089 REWIND_CFP({ 2090 rb_undef(cbase, SYM2ID(sym)); 2091 INC_VM_STATE_VERSION(); 2092 }); 2093 return Qnil; 2094} 2095 2096static VALUE 2097m_core_set_postexe(VALUE self, VALUE iseqval) 2098{ 2099 REWIND_CFP({ 2100 rb_iseq_t *blockiseq; 2101 rb_block_t *blockptr; 2102 rb_thread_t *th = GET_THREAD(); 2103 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); 2104 VALUE proc; 2105 2106 if (cfp == 0) { 2107 rb_bug("m_core_set_postexe: unreachable"); 2108 } 2109 2110 GetISeqPtr(iseqval, blockiseq); 2111 2112 blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); 2113 blockptr->iseq = blockiseq; 2114 blockptr->proc = 0; 2115 2116 proc = rb_vm_make_proc(th, blockptr, rb_cProc); 2117 rb_set_end_proc(rb_call_end_proc, proc); 2118 }); 2119 return Qnil; 2120} 2121 2122static VALUE 2123m_core_hash_from_ary(VALUE self, VALUE ary) 2124{ 2125 VALUE hash = rb_hash_new(); 2126 int i; 2127 2128 if (RUBY_DTRACE_HASH_CREATE_ENABLED()) { 2129 RUBY_DTRACE_HASH_CREATE(RARRAY_LEN(ary), rb_sourcefile(), rb_sourceline()); 2130 } 2131 2132 assert(RARRAY_LEN(ary) % 2 == 0); 2133 for (i=0; i<RARRAY_LEN(ary); i+=2) { 2134 rb_hash_aset(hash, RARRAY_PTR(ary)[i], RARRAY_PTR(ary)[i+1]); 2135 } 2136 2137 return hash; 2138} 2139 2140static VALUE 2141m_core_hash_merge_ary(VALUE self, VALUE hash, VALUE ary) 2142{ 2143 int i; 2144 2145 assert(RARRAY_LEN(ary) % 2 == 0); 2146 for (i=0; i<RARRAY_LEN(ary); i+=2) { 2147 rb_hash_aset(hash, RARRAY_PTR(ary)[i], RARRAY_PTR(ary)[i+1]); 2148 } 2149 2150 return hash; 2151} 2152 2153static VALUE 2154m_core_hash_merge_ptr(int argc, VALUE *argv, VALUE recv) 2155{ 2156 int i; 2157 VALUE hash = argv[0]; 2158 2159 for (i=1; i<argc; i+=2) { 2160 rb_hash_aset(hash, argv[i], argv[i+1]); 2161 } 2162 2163 return hash; 2164} 2165 2166static int 2167kwmerge_ii(st_data_t *key, st_data_t *value, st_data_t arg, int existing) 2168{ 2169 if (existing) return ST_STOP; 2170 *value = arg; 2171 return ST_CONTINUE; 2172} 2173 2174static int 2175kwmerge_i(VALUE key, VALUE value, VALUE hash) 2176{ 2177 if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL); 2178 st_update(RHASH_TBL(hash), key, kwmerge_ii, (st_data_t)value); 2179 return ST_CONTINUE; 2180} 2181 2182static VALUE 2183m_core_hash_merge_kwd(VALUE recv, VALUE hash, VALUE kw) 2184{ 2185 kw = rb_convert_type(kw, T_HASH, "Hash", "to_hash"); 2186 rb_hash_foreach(kw, kwmerge_i, hash); 2187 return hash; 2188} 2189 2190extern VALUE *rb_gc_stack_start; 2191extern size_t rb_gc_stack_maxsize; 2192#ifdef __ia64 2193extern VALUE *rb_gc_register_stack_start; 2194#endif 2195 2196/* debug functions */ 2197 2198/* :nodoc: */ 2199static VALUE 2200sdr(void) 2201{ 2202 rb_vm_bugreport(); 2203 return Qnil; 2204} 2205 2206/* :nodoc: */ 2207static VALUE 2208nsdr(void) 2209{ 2210 VALUE ary = rb_ary_new(); 2211#if HAVE_BACKTRACE 2212#include <execinfo.h> 2213#define MAX_NATIVE_TRACE 1024 2214 static void *trace[MAX_NATIVE_TRACE]; 2215 int n = backtrace(trace, MAX_NATIVE_TRACE); 2216 char **syms = backtrace_symbols(trace, n); 2217 int i; 2218 2219 if (syms == 0) { 2220 rb_memerror(); 2221 } 2222 2223 for (i=0; i<n; i++) { 2224 rb_ary_push(ary, rb_str_new2(syms[i])); 2225 } 2226 free(syms); /* OK */ 2227#endif 2228 return ary; 2229} 2230 2231#if VM_COLLECT_USAGE_DETAILS 2232static VALUE usage_analysis_insn_stop(VALUE self); 2233static VALUE usage_analysis_operand_stop(VALUE self); 2234static VALUE usage_analysis_register_stop(VALUE self); 2235#endif 2236 2237void 2238Init_VM(void) 2239{ 2240 VALUE opts; 2241 VALUE klass; 2242 VALUE fcore; 2243 2244 /* ::RubyVM */ 2245 rb_cRubyVM = rb_define_class("RubyVM", rb_cObject); 2246 rb_undef_alloc_func(rb_cRubyVM); 2247 rb_undef_method(CLASS_OF(rb_cRubyVM), "new"); 2248 2249 /* FrozenCore (hidden) */ 2250 fcore = rb_class_new(rb_cBasicObject); 2251 RBASIC(fcore)->flags = T_ICLASS; 2252 klass = rb_singleton_class(fcore); 2253 rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3); 2254 rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2); 2255 rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2); 2256 rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3); 2257 rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3); 2258 rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1); 2259 rb_define_method_id(klass, id_core_hash_from_ary, m_core_hash_from_ary, 1); 2260 rb_define_method_id(klass, id_core_hash_merge_ary, m_core_hash_merge_ary, 2); 2261 rb_define_method_id(klass, id_core_hash_merge_ptr, m_core_hash_merge_ptr, -1); 2262 rb_define_method_id(klass, id_core_hash_merge_kwd, m_core_hash_merge_kwd, 2); 2263 rb_define_method_id(klass, idProc, rb_block_proc, 0); 2264 rb_define_method_id(klass, idLambda, rb_block_lambda, 0); 2265 rb_obj_freeze(fcore); 2266 rb_gc_register_mark_object(fcore); 2267 rb_mRubyVMFrozenCore = fcore; 2268 2269 /* ::RubyVM::Env */ 2270 rb_cEnv = rb_define_class_under(rb_cRubyVM, "Env", rb_cObject); 2271 rb_undef_alloc_func(rb_cEnv); 2272 rb_undef_method(CLASS_OF(rb_cEnv), "new"); 2273 2274 /* ::Thread */ 2275 rb_cThread = rb_define_class("Thread", rb_cObject); 2276 rb_undef_alloc_func(rb_cThread); 2277 2278#if VM_COLLECT_USAGE_DETAILS 2279 /* ::RubyVM::USAGE_ANALYSIS_* */ 2280 rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_INSN", rb_hash_new()); 2281 rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_REGS", rb_hash_new()); 2282 rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_INSN_BIGRAM", rb_hash_new()); 2283 2284 rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_STOP", usage_analysis_insn_stop, 0); 2285 rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_STOP", usage_analysis_operand_stop, 0); 2286 rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_STOP", usage_analysis_register_stop, 0); 2287#endif 2288 2289 /* ::RubyVM::OPTS, which shows vm build options */ 2290 rb_define_const(rb_cRubyVM, "OPTS", opts = rb_ary_new()); 2291 2292#if OPT_DIRECT_THREADED_CODE 2293 rb_ary_push(opts, rb_str_new2("direct threaded code")); 2294#elif OPT_TOKEN_THREADED_CODE 2295 rb_ary_push(opts, rb_str_new2("token threaded code")); 2296#elif OPT_CALL_THREADED_CODE 2297 rb_ary_push(opts, rb_str_new2("call threaded code")); 2298#endif 2299 2300#if OPT_STACK_CACHING 2301 rb_ary_push(opts, rb_str_new2("stack caching")); 2302#endif 2303#if OPT_OPERANDS_UNIFICATION 2304 rb_ary_push(opts, rb_str_new2("operands unification]")); 2305#endif 2306#if OPT_INSTRUCTIONS_UNIFICATION 2307 rb_ary_push(opts, rb_str_new2("instructions unification")); 2308#endif 2309#if OPT_INLINE_METHOD_CACHE 2310 rb_ary_push(opts, rb_str_new2("inline method cache")); 2311#endif 2312#if OPT_BLOCKINLINING 2313 rb_ary_push(opts, rb_str_new2("block inlining")); 2314#endif 2315 2316 /* ::RubyVM::INSTRUCTION_NAMES */ 2317 rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", rb_insns_name_array()); 2318 2319 /* ::RubyVM::DEFAULT_PARAMS 2320 * This constant variable shows VM's default parameters. 2321 * Note that changing these values does not affect VM exection. 2322 * Specification is not stable and you should not depend on this value. 2323 * Of course, this constant is MRI specific. 2324 */ 2325 rb_define_const(rb_cRubyVM, "DEFAULT_PARAMS", vm_default_params()); 2326 2327 /* debug functions ::RubyVM::SDR(), ::RubyVM::NSDR() */ 2328#if VMDEBUG 2329 rb_define_singleton_method(rb_cRubyVM, "SDR", sdr, 0); 2330 rb_define_singleton_method(rb_cRubyVM, "NSDR", nsdr, 0); 2331#else 2332 (void)sdr; 2333 (void)nsdr; 2334#endif 2335 2336 /* VM bootstrap: phase 2 */ 2337 { 2338 rb_vm_t *vm = ruby_current_vm; 2339 rb_thread_t *th = GET_THREAD(); 2340 VALUE filename = rb_str_new2("<main>"); 2341 volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP); 2342 volatile VALUE th_self; 2343 rb_iseq_t *iseq; 2344 2345 /* create vm object */ 2346 vm->self = TypedData_Wrap_Struct(rb_cRubyVM, &vm_data_type, vm); 2347 2348 /* create main thread */ 2349 th_self = th->self = TypedData_Wrap_Struct(rb_cThread, &thread_data_type, th); 2350 rb_iv_set(th_self, "locals", rb_hash_new()); 2351 vm->main_thread = th; 2352 vm->running_thread = th; 2353 th->vm = vm; 2354 th->top_wrapper = 0; 2355 th->top_self = rb_vm_top_self(); 2356 rb_thread_set_current(th); 2357 2358 vm->living_threads = st_init_numtable(); 2359 st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id); 2360 2361 rb_gc_register_mark_object(iseqval); 2362 GetISeqPtr(iseqval, iseq); 2363 th->cfp->iseq = iseq; 2364 th->cfp->pc = iseq->iseq_encoded; 2365 th->cfp->self = th->top_self; 2366 th->cfp->klass = Qnil; 2367 2368 /* 2369 * The Binding of the top level scope 2370 */ 2371 rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new()); 2372 } 2373 vm_init_redefined_flag(); 2374 2375 /* vm_backtrace.c */ 2376 Init_vm_backtrace(); 2377 VM_PROFILE_ATEXIT(); 2378} 2379 2380void 2381rb_vm_set_progname(VALUE filename) 2382{ 2383 rb_thread_t *th = GET_VM()->main_thread; 2384 rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size); 2385 --cfp; 2386 cfp->iseq->location.path = filename; 2387} 2388 2389#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE 2390struct rb_objspace *rb_objspace_alloc(void); 2391#endif 2392 2393void 2394Init_BareVM(void) 2395{ 2396 /* VM bootstrap: phase 1 */ 2397 rb_vm_t * vm = ruby_mimmalloc(sizeof(*vm)); 2398 rb_thread_t * th = ruby_mimmalloc(sizeof(*th)); 2399 if (!vm || !th) { 2400 fprintf(stderr, "[FATAL] failed to allocate memory\n"); 2401 exit(EXIT_FAILURE); 2402 } 2403 MEMZERO(th, rb_thread_t, 1); 2404 rb_thread_set_current_raw(th); 2405 2406 vm_init2(vm); 2407#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE 2408 vm->objspace = rb_objspace_alloc(); 2409#endif 2410 ruby_current_vm = vm; 2411 2412 Init_native_thread(); 2413 th->vm = vm; 2414 th_init(th, 0); 2415 ruby_thread_init_stack(th); 2416} 2417 2418/* top self */ 2419 2420static VALUE 2421main_to_s(VALUE obj) 2422{ 2423 return rb_str_new2("main"); 2424} 2425 2426VALUE 2427rb_vm_top_self(void) 2428{ 2429 return GET_VM()->top_self; 2430} 2431 2432void 2433Init_top_self(void) 2434{ 2435 rb_vm_t *vm = GET_VM(); 2436 2437 vm->top_self = rb_obj_alloc(rb_cObject); 2438 rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0); 2439 rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s"); 2440 2441 /* initialize mark object array */ 2442 vm->mark_object_ary = rb_ary_tmp_new(1); 2443} 2444 2445VALUE * 2446ruby_vm_verbose_ptr(rb_vm_t *vm) 2447{ 2448 return &vm->verbose; 2449} 2450 2451VALUE * 2452ruby_vm_debug_ptr(rb_vm_t *vm) 2453{ 2454 return &vm->debug; 2455} 2456 2457VALUE * 2458rb_ruby_verbose_ptr(void) 2459{ 2460 return ruby_vm_verbose_ptr(GET_VM()); 2461} 2462 2463VALUE * 2464rb_ruby_debug_ptr(void) 2465{ 2466 return ruby_vm_debug_ptr(GET_VM()); 2467} 2468 2469/* iseq.c */ 2470VALUE insn_operand_intern(rb_iseq_t *iseq, 2471 VALUE insn, int op_no, VALUE op, 2472 int len, size_t pos, VALUE *pnop, VALUE child); 2473 2474#if VM_COLLECT_USAGE_DETAILS 2475 2476#define HASH_ASET(h, k, v) st_insert(RHASH_TBL(h), (st_data_t)(k), (st_data_t)(v)) 2477 2478/* uh = { 2479 * insn(Fixnum) => ihash(Hash) 2480 * } 2481 * ihash = { 2482 * -1(Fixnum) => count, # insn usage 2483 * 0(Fixnum) => ophash, # operand usage 2484 * } 2485 * ophash = { 2486 * val(interned string) => count(Fixnum) 2487 * } 2488 */ 2489static void 2490vm_analysis_insn(int insn) 2491{ 2492 ID usage_hash; 2493 ID bigram_hash; 2494 static int prev_insn = -1; 2495 2496 VALUE uh; 2497 VALUE ihash; 2498 VALUE cv; 2499 2500 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 2501 CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM"); 2502 uh = rb_const_get(rb_cRubyVM, usage_hash); 2503 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 2504 ihash = rb_hash_new(); 2505 HASH_ASET(uh, INT2FIX(insn), ihash); 2506 } 2507 if ((cv = rb_hash_aref(ihash, INT2FIX(-1))) == Qnil) { 2508 cv = INT2FIX(0); 2509 } 2510 HASH_ASET(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1)); 2511 2512 /* calc bigram */ 2513 if (prev_insn != -1) { 2514 VALUE bi; 2515 VALUE ary[2]; 2516 VALUE cv; 2517 2518 ary[0] = INT2FIX(prev_insn); 2519 ary[1] = INT2FIX(insn); 2520 bi = rb_ary_new4(2, &ary[0]); 2521 2522 uh = rb_const_get(rb_cRubyVM, bigram_hash); 2523 if ((cv = rb_hash_aref(uh, bi)) == Qnil) { 2524 cv = INT2FIX(0); 2525 } 2526 HASH_ASET(uh, bi, INT2FIX(FIX2INT(cv) + 1)); 2527 } 2528 prev_insn = insn; 2529} 2530 2531static void 2532vm_analysis_operand(int insn, int n, VALUE op) 2533{ 2534 ID usage_hash; 2535 2536 VALUE uh; 2537 VALUE ihash; 2538 VALUE ophash; 2539 VALUE valstr; 2540 VALUE cv; 2541 2542 CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN"); 2543 2544 uh = rb_const_get(rb_cRubyVM, usage_hash); 2545 if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) { 2546 ihash = rb_hash_new(); 2547 HASH_ASET(uh, INT2FIX(insn), ihash); 2548 } 2549 if ((ophash = rb_hash_aref(ihash, INT2FIX(n))) == Qnil) { 2550 ophash = rb_hash_new(); 2551 HASH_ASET(ihash, INT2FIX(n), ophash); 2552 } 2553 /* intern */ 2554 valstr = insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0); 2555 2556 /* set count */ 2557 if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) { 2558 cv = INT2FIX(0); 2559 } 2560 HASH_ASET(ophash, valstr, INT2FIX(FIX2INT(cv) + 1)); 2561} 2562 2563static void 2564vm_analysis_register(int reg, int isset) 2565{ 2566 ID usage_hash; 2567 VALUE uh; 2568 VALUE valstr; 2569 static const char regstrs[][5] = { 2570 "pc", /* 0 */ 2571 "sp", /* 1 */ 2572 "ep", /* 2 */ 2573 "cfp", /* 3 */ 2574 "self", /* 4 */ 2575 "iseq", /* 5 */ 2576 }; 2577 static const char getsetstr[][4] = { 2578 "get", 2579 "set", 2580 }; 2581 static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2]; 2582 2583 VALUE cv; 2584 2585 CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS"); 2586 if (syms[0] == 0) { 2587 char buff[0x10]; 2588 int i; 2589 2590 for (i = 0; i < (int)(sizeof(regstrs) / sizeof(regstrs[0])); i++) { 2591 int j; 2592 for (j = 0; j < 2; j++) { 2593 snprintf(buff, 0x10, "%d %s %-4s", i, getsetstr[j], regstrs[i]); 2594 syms[i][j] = ID2SYM(rb_intern(buff)); 2595 } 2596 } 2597 } 2598 valstr = syms[reg][isset]; 2599 2600 uh = rb_const_get(rb_cRubyVM, usage_hash); 2601 if ((cv = rb_hash_aref(uh, valstr)) == Qnil) { 2602 cv = INT2FIX(0); 2603 } 2604 HASH_ASET(uh, valstr, INT2FIX(FIX2INT(cv) + 1)); 2605} 2606 2607#undef HASH_ASET 2608 2609void (*ruby_vm_collect_usage_func_insn)(int insn) = vm_analysis_insn; 2610void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = vm_analysis_operand; 2611void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = vm_analysis_register; 2612 2613/* :nodoc: */ 2614static VALUE 2615usage_analysis_insn_stop(VALUE self) 2616{ 2617 ruby_vm_collect_usage_func_insn = 0; 2618 return Qnil; 2619} 2620 2621/* :nodoc: */ 2622static VALUE 2623usage_analysis_operand_stop(VALUE self) 2624{ 2625 ruby_vm_collect_usage_func_operand = 0; 2626 return Qnil; 2627} 2628 2629/* :nodoc: */ 2630static VALUE 2631usage_analysis_register_stop(VALUE self) 2632{ 2633 ruby_vm_collect_usage_func_register = 0; 2634 return Qnil; 2635} 2636 2637#else 2638 2639void (*ruby_vm_collect_usage_func_insn)(int insn) = NULL; 2640void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = NULL; 2641void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = NULL; 2642 2643#endif 2644 2645#if VM_COLLECT_USAGE_DETAILS 2646/* @param insn instruction number */ 2647static void 2648vm_collect_usage_insn(int insn) 2649{ 2650 if (RUBY_DTRACE_INSN_ENABLED()) { 2651 RUBY_DTRACE_INSN(rb_insns_name(insn)); 2652 } 2653 if (ruby_vm_collect_usage_func_insn) 2654 (*ruby_vm_collect_usage_func_insn)(insn); 2655} 2656 2657/* @param insn instruction number 2658 * @param n n-th operand 2659 * @param op operand value 2660 */ 2661static void 2662vm_collect_usage_operand(int insn, int n, VALUE op) 2663{ 2664 if (RUBY_DTRACE_INSN_OPERAND_ENABLED()) { 2665 VALUE valstr; 2666 2667 valstr = insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0); 2668 2669 RUBY_DTRACE_INSN_OPERAND(RSTRING_PTR(valstr), rb_insns_name(insn)); 2670 RB_GC_GUARD(valstr); 2671 } 2672 if (ruby_vm_collect_usage_func_operand) 2673 (*ruby_vm_collect_usage_func_operand)(insn, n, op); 2674} 2675 2676/* @param reg register id. see code of vm_analysis_register() */ 2677/* @param iseset 0: read, 1: write */ 2678static void 2679vm_collect_usage_register(int reg, int isset) 2680{ 2681 if (ruby_vm_collect_usage_func_register) 2682 (*ruby_vm_collect_usage_func_register)(reg, isset); 2683} 2684#endif 2685 2686