Ruby  2.1.3p242(2014-09-19revision47630)
vm.c
Go to the documentation of this file.
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 
24 static inline VALUE *
26 {
27  while (!VM_EP_LEP_P(ep)) {
28  ep = VM_EP_PREV_EP(ep);
29  }
30  return ep;
31 }
32 
33 VALUE *
35 {
36  return VM_EP_LEP(ep);
37 }
38 
39 static inline VALUE *
41 {
42  return VM_EP_LEP(cfp->ep);
43 }
44 
45 static inline VALUE *
47 {
48  return VM_EP_PREV_EP((cfp)->ep);
49 }
50 
51 static inline rb_block_t *
53 {
54  VALUE *ep = VM_CF_LEP(cfp);
55  return VM_EP_BLOCK_PTR(ep);
56 }
57 
58 rb_block_t *
60 {
61  return VM_CF_BLOCK_PTR(cfp);
62 }
63 
64 #if VM_COLLECT_USAGE_DETAILS
65 static void vm_collect_usage_operand(int insn, int n, VALUE op);
66 static void vm_collect_usage_insn(int insn);
67 static void vm_collect_usage_register(int reg, int isset);
68 #endif
69 
70 static VALUE
71 vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
72  int argc, const VALUE *argv, const rb_block_t *blockptr);
73 
77 
78 #include "vm_insnhelper.h"
79 #include "vm_insnhelper.c"
80 #include "vm_exec.h"
81 #include "vm_exec.c"
82 
83 #include "vm_method.c"
84 #include "vm_eval.c"
85 
86 #include <assert.h>
87 
88 #define BUFSIZE 0x100
89 #define PROCDEBUG 0
90 
93 {
94  return NEXT_CLASS_SERIAL();
95 }
96 
101 
107 
108 static void thread_free(void *ptr);
109 
110 void
112 {
114 }
115 
116 /*
117  * call-seq:
118  * RubyVM.stat -> Hash
119  * RubyVM.stat(hsh) -> hsh
120  * RubyVM.stat(Symbol) -> Numeric
121  *
122  * Returns a Hash containing implementation-dependent counters inside the VM.
123  *
124  * This hash includes information about method/constant cache serials:
125  *
126  * {
127  * :global_method_state=>251,
128  * :global_constant_state=>481,
129  * :class_serial=>9029
130  * }
131  *
132  * The contents of the hash are implementation specific and may be changed in
133  * the future.
134  *
135  * This method is only expected to work on C Ruby.
136  */
137 
138 static VALUE
140 {
141  static VALUE sym_global_method_state, sym_global_constant_state, sym_class_serial;
142  VALUE arg = Qnil;
143  VALUE hash = Qnil, key = Qnil;
144 
145  if (rb_scan_args(argc, argv, "01", &arg) == 1) {
146  if (SYMBOL_P(arg))
147  key = arg;
148  else if (RB_TYPE_P(arg, T_HASH))
149  hash = arg;
150  else
151  rb_raise(rb_eTypeError, "non-hash or symbol given");
152  } else if (arg == Qnil) {
153  hash = rb_hash_new();
154  }
155 
156  if (sym_global_method_state == 0) {
157 #define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
158  S(global_method_state);
159  S(global_constant_state);
160  S(class_serial);
161 #undef S
162  }
163 
164 #define SET(name, attr) \
165  if (key == sym_##name) \
166  return SERIALT2NUM(attr); \
167  else if (hash != Qnil) \
168  rb_hash_aset(hash, sym_##name, SERIALT2NUM(attr));
169 
170  SET(global_method_state, ruby_vm_global_method_state);
171  SET(global_constant_state, ruby_vm_global_constant_state);
172  SET(class_serial, ruby_vm_class_serial);
173 #undef SET
174 
175  if (key != Qnil) /* matched key should return above */
176  rb_raise(rb_eArgError, "unknown key: %s", RSTRING_PTR(rb_id2str(SYM2ID(key))));
177 
178  return hash;
179 }
180 
181 /* control stack frame */
182 
183 static void
185 {
186  rb_iseq_t *iseq;
187  GetISeqPtr(iseqval, iseq);
188 
189  if (iseq->type != ISEQ_TYPE_TOP) {
190  rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
191  }
192 
193  /* for return */
196  iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
197 }
198 
199 static void
200 vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t *base_block)
201 {
202  rb_iseq_t *iseq;
203  GetISeqPtr(iseqval, iseq);
204 
206  base_block->self, base_block->klass,
207  VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded,
208  th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
209 
210  if (cref) {
211  th->cfp->ep[-1] = (VALUE)cref;
212  }
213 }
214 
215 static void
217 {
218  VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
219  rb_binding_t *bind;
220  rb_iseq_t *iseq;
221  rb_env_t *env;
222 
223  GetBindingPtr(toplevel_binding, bind);
224  GetEnvPtr(bind->env, env);
225  vm_set_eval_stack(th, iseqval, 0, &env->block);
226 
227  /* save binding */
228  GetISeqPtr(iseqval, iseq);
229  if (bind && iseq->local_size > 0) {
230  bind->env = rb_vm_make_env_object(th, th->cfp);
231  }
232 }
233 
236 {
237  while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
238  if (cfp->iseq) {
239  return (rb_control_frame_t *)cfp;
240  }
242  }
243  return 0;
244 }
245 
248 {
249  while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
250  if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
251  return (rb_control_frame_t *)cfp;
252  }
254  }
255  return 0;
256 }
257 
258 static rb_control_frame_t *
260 {
261  if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
262  return cfp;
263  }
264 
266 
267  while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
268  if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
269  return cfp;
270  }
271 
272  if ((cfp->flag & VM_FRAME_FLAG_PASSED) == 0) {
273  break;
274  }
276  }
277  return 0;
278 }
279 
280 void
282 {
283  rb_thread_t *th = GET_THREAD();
284  const rb_method_entry_t *me = th->cfp->me;
287  vm_pop_frame(th);
288 }
289 
290 void
292 {
293  /* check skipped frame */
294  while (th->cfp != cfp) {
295 #if VMDEBUG
296  printf("skipped frame: %s\n", vm_frametype_name(th->cfp));
297 #endif
298  if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) {
299  vm_pop_frame(th);
300  }
301  else { /* unlikely path */
303  }
304  }
305 }
306 
307 /* obsolete */
308 void
310 {
311  rb_thread_t *th = GET_THREAD();
312  vm_pop_frame(th);
313 }
314 
315 /* at exit */
316 
317 void
319 {
321 }
322 
323 static void
325 {
326  VALUE hook = (VALUE)&vm->at_exit;
327 
328  while (RARRAY_LEN(hook) > 0) {
329  typedef void rb_vm_at_exit_func(rb_vm_t*);
330  rb_vm_at_exit_func *func = (rb_vm_at_exit_func*)rb_ary_pop(hook);
331  (*func)(vm);
332  }
333  rb_ary_free(hook);
334 }
335 
336 /* Env */
337 
338 /*
339  env{
340  env[0] // special (block or prev env)
341  env[1] // env object
342  };
343  */
344 
345 #define ENV_IN_HEAP_P(th, env) \
346  (!((th)->stack <= (env) && (env) < ((th)->stack + (th)->stack_size)))
347 #define ENV_VAL(env) ((env)[1])
348 
349 static void
350 env_mark(void * const ptr)
351 {
352  RUBY_MARK_ENTER("env");
353  if (ptr) {
354  const rb_env_t * const env = ptr;
355 
356  if (env->env) {
357  /* TODO: should mark more restricted range */
358  RUBY_GC_INFO("env->env\n");
359  rb_gc_mark_locations(env->env, env->env + env->env_size);
360  }
361 
362  RUBY_GC_INFO("env->prev_envval\n");
366 
367  if (env->block.iseq) {
368  if (BUILTIN_TYPE(env->block.iseq) == T_NODE) {
370  }
371  else {
373  }
374  }
375  }
376  RUBY_MARK_LEAVE("env");
377 }
378 
379 static void
380 env_free(void * const ptr)
381 {
382  RUBY_FREE_ENTER("env");
383  if (ptr) {
384  rb_env_t *const env = ptr;
386  ruby_xfree(ptr);
387  }
388  RUBY_FREE_LEAVE("env");
389 }
390 
391 static size_t
392 env_memsize(const void *ptr)
393 {
394  if (ptr) {
395  const rb_env_t * const env = ptr;
396  size_t size = sizeof(rb_env_t);
397  if (env->env) {
398  size += env->env_size * sizeof(VALUE);
399  }
400  return size;
401  }
402  return 0;
403 }
404 
406  "VM/env",
409 };
410 
411 static VALUE
413 {
414  VALUE obj;
415  rb_env_t *env;
416  obj = TypedData_Make_Struct(rb_cEnv, rb_env_t, &env_data_type, env);
417  env->env = 0;
418  env->prev_envval = 0;
419  env->block.iseq = 0;
420  return obj;
421 }
422 
423 static VALUE check_env_value(VALUE envval);
424 
425 static int
426 check_env(rb_env_t * const env)
427 {
428  fprintf(stderr, "---\n");
429  fprintf(stderr, "envptr: %p\n", (void *)&env->block.ep[0]);
430  fprintf(stderr, "envval: %10p ", (void *)env->block.ep[1]);
431  dp(env->block.ep[1]);
432  fprintf(stderr, "ep: %10p\n", (void *)env->block.ep);
433  if (env->prev_envval) {
434  fprintf(stderr, ">>\n");
436  fprintf(stderr, "<<\n");
437  }
438  return 1;
439 }
440 
441 static VALUE
443 {
444  rb_env_t *env;
445  GetEnvPtr(envval, env);
446 
447  if (check_env(env)) {
448  return envval;
449  }
450  rb_bug("invalid env");
451  return Qnil; /* unreachable */
452 }
453 
454 static VALUE
456  VALUE *envptr, VALUE * const endptr)
457 {
458  VALUE envval, penvval = 0;
459  rb_env_t *env;
460  VALUE *nenvptr;
461  int i, local_size;
462 
463  if (ENV_IN_HEAP_P(th, envptr)) {
464  return ENV_VAL(envptr);
465  }
466 
467  if (envptr != endptr) {
468  VALUE *penvptr = GC_GUARDED_PTR_REF(*envptr);
469  rb_control_frame_t *pcfp = cfp;
470 
471  if (ENV_IN_HEAP_P(th, penvptr)) {
472  penvval = ENV_VAL(penvptr);
473  }
474  else {
475  while (pcfp->ep != penvptr) {
476  pcfp++;
477  if (pcfp->ep == 0) {
478  SDR();
479  rb_bug("invalid ep");
480  }
481  }
482  penvval = vm_make_env_each(th, pcfp, penvptr, endptr);
483  *envptr = VM_ENVVAL_PREV_EP_PTR(pcfp->ep);
484  }
485  }
486 
487  /* allocate env */
488  envval = env_alloc();
489  GetEnvPtr(envval, env);
490 
491  if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
492  local_size = 2;
493  }
494  else {
495  local_size = cfp->iseq->local_size;
496  }
497 
498  env->env_size = local_size + 1 + 1;
499  env->local_size = local_size;
500  env->env = ALLOC_N(VALUE, env->env_size);
501  env->prev_envval = penvval;
502 
503  for (i = 0; i <= local_size; i++) {
504  env->env[i] = envptr[-local_size + i];
505 #if 0
506  fprintf(stderr, "%2d ", &envptr[-local_size + i] - th->stack); dp(env->env[i]);
507  if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
508  /* clear value stack for GC */
509  envptr[-local_size + i] = 0;
510  }
511 #endif
512  }
513 
514  *envptr = envval; /* GC mark */
515  nenvptr = &env->env[i - 1];
516  nenvptr[1] = envval; /* frame self */
517 
518  /* reset ep in cfp */
519  cfp->ep = nenvptr;
520 
521  /* as Binding */
522  env->block.self = cfp->self;
523  env->block.ep = cfp->ep;
524  env->block.iseq = cfp->iseq;
525 
526  if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
527  /* TODO */
528  env->block.iseq = 0;
529  }
530  return envval;
531 }
532 
533 static int
535 {
536  int i;
537  if (!iseq) return 0;
538  for (i = 0; i < iseq->local_table_size; i++) {
539  ID lid = iseq->local_table[i];
540  if (rb_is_local_id(lid)) {
541  rb_ary_push(ary, ID2SYM(lid));
542  }
543  }
544  return 1;
545 }
546 
547 static int
549 {
550 
551  while (collect_local_variables_in_iseq(env->block.iseq, ary),
552  env->prev_envval) {
553  GetEnvPtr(env->prev_envval, env);
554  }
555  return 0;
556 }
557 
558 static int
560 {
561  if (ENV_IN_HEAP_P(th, ep)) {
562  rb_env_t *env;
563  GetEnvPtr(ENV_VAL(ep), env);
565  return 1;
566  }
567  else {
568  return 0;
569  }
570 }
571 
572 static void vm_rewrite_ep_in_errinfo(rb_thread_t *th);
574 static VALUE vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp, VALUE *blockprocptr);
575 
576 VALUE
578 {
579  VALUE blockprocval;
580  return vm_make_env_object(th, cfp, &blockprocval);
581 }
582 
583 static VALUE
585 {
586  VALUE envval;
587  VALUE *lep = VM_CF_LEP(cfp);
588  rb_block_t *blockptr = VM_EP_BLOCK_PTR(lep);
589 
590  if (blockptr) {
591  VALUE blockprocval = vm_make_proc_from_block(th, blockptr);
592  rb_proc_t *p;
593  GetProcPtr(blockprocval, p);
594  lep[0] = VM_ENVVAL_BLOCK_PTR(&p->block);
595  *blockprocptr = blockprocval;
596  }
597 
598  envval = vm_make_env_each(th, cfp, cfp->ep, lep);
600 
601  if (PROCDEBUG) {
602  check_env_value(envval);
603  }
604 
605  return envval;
606 }
607 
608 static void
610 {
611  rb_control_frame_t *cfp = th->cfp;
612  while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
613  /* rewrite ep in errinfo to point to heap */
614  if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
615  (cfp->iseq->type == ISEQ_TYPE_RESCUE ||
616  cfp->iseq->type == ISEQ_TYPE_ENSURE)) {
617  VALUE errinfo = cfp->ep[-2]; /* #$! */
618  if (RB_TYPE_P(errinfo, T_NODE)) {
619  VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(errinfo);
620  if (! ENV_IN_HEAP_P(th, escape_ep)) {
621  VALUE epval = *escape_ep;
622  if (!SPECIAL_CONST_P(epval) && RBASIC(epval)->klass == rb_cEnv) {
623  rb_env_t *epenv;
624  GetEnvPtr(epval, epenv);
625  SET_THROWOBJ_CATCH_POINT(errinfo, (VALUE)(epenv->env + epenv->local_size));
626  }
627  }
628  }
629  }
631  }
632 }
633 
634 void
636 {
637  rb_control_frame_t *cfp = th->cfp;
638  while ((cfp = rb_vm_get_binding_creatable_next_cfp(th, cfp)) != 0) {
639  rb_vm_make_env_object(th, cfp);
641  }
642 }
643 
644 /* Proc */
645 
646 static VALUE
648 {
649  if (!block->proc) {
650  block->proc = rb_vm_make_proc(th, block, rb_cProc);
651  }
652  return block->proc;
653 }
654 
655 VALUE
656 rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
657 {
658  VALUE procval, envval, blockprocval = 0;
659  rb_proc_t *proc;
661 
662  if (block->proc) {
663  rb_bug("rb_vm_make_proc: Proc value is already created.");
664  }
665 
666  envval = vm_make_env_object(th, cfp, &blockprocval);
667 
668  if (PROCDEBUG) {
669  check_env_value(envval);
670  }
671  procval = rb_proc_alloc(klass);
672  GetProcPtr(procval, proc);
673  proc->blockprocval = blockprocval;
674  proc->block.self = block->self;
675  proc->block.klass = block->klass;
676  proc->block.ep = block->ep;
677  proc->block.iseq = block->iseq;
678  proc->block.proc = procval;
679  proc->envval = envval;
680  proc->safe_level = th->safe_level;
681 
682  if (VMDEBUG) {
683  if (th->stack < block->ep && block->ep < th->stack + th->stack_size) {
684  rb_bug("invalid ptr: block->ep");
685  }
686  }
687 
688  return procval;
689 }
690 
691 VALUE *
692 rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynvars)
693 {
694  VALUE envval = bind->env, path = bind->path, iseqval;
695  rb_env_t *env;
696  rb_block_t *base_block;
697  rb_thread_t *th = GET_THREAD();
698  rb_iseq_t *base_iseq;
699  NODE *node = 0;
700  ID minibuf[4], *dyns = minibuf;
701  VALUE idtmp = 0;
702 
703  if (dyncount < 0) return 0;
704 
705  GetEnvPtr(envval, env);
706 
707  base_block = &env->block;
708  base_iseq = base_block->iseq;
709 
710  if (dyncount >= numberof(minibuf)) dyns = ALLOCV_N(ID, idtmp, dyncount + 1);
711 
712  dyns[0] = dyncount;
713  MEMCPY(dyns + 1, dynvars, ID, dyncount);
714  node = NEW_NODE(NODE_SCOPE, dyns, 0, 0);
715 
716  iseqval = rb_iseq_new(node, base_iseq->location.label, path, path,
717  base_iseq->self, ISEQ_TYPE_EVAL);
718  node->u1.tbl = 0; /* reset table */
719  ALLOCV_END(idtmp);
720 
721  vm_set_eval_stack(th, iseqval, 0, base_block);
722  bind->env = rb_vm_make_env_object(th, th->cfp);
723  vm_pop_frame(th);
724  GetEnvPtr(bind->env, env);
725 
726  return env->env;
727 }
728 
729 /* C -> Ruby: block */
730 
731 static inline VALUE
733  VALUE self, int argc, const VALUE *argv,
734  const rb_block_t *blockptr, const NODE *cref,
735  VALUE defined_class)
736 {
737  if (SPECIAL_CONST_P(block->iseq)) {
738  return Qnil;
739  }
740  else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
741  VALUE ret;
742  const rb_iseq_t *iseq = block->iseq;
743  const rb_control_frame_t *cfp;
744  int i, opt_pc, arg_size = iseq->arg_size;
746  const rb_method_entry_t *me = th->passed_bmethod_me;
747  th->passed_bmethod_me = 0;
748  cfp = th->cfp;
749 
750  for (i=0; i<argc; i++) {
751  cfp->sp[i] = argv[i];
752  }
753 
754  opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
755  type == VM_FRAME_MAGIC_LAMBDA);
756 
757  if (me != 0) {
758  /* bmethod */
760  self, defined_class,
761  VM_ENVVAL_PREV_EP_PTR(block->ep),
762  iseq->iseq_encoded + opt_pc,
763  cfp->sp + arg_size, iseq->local_size - arg_size,
764  me, iseq->stack_max);
765 
767  EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->klass, Qnil);
768  }
769  else {
770  vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
771  self, defined_class,
772  VM_ENVVAL_PREV_EP_PTR(block->ep),
773  iseq->iseq_encoded + opt_pc,
774  cfp->sp + arg_size, iseq->local_size - arg_size,
775  0, iseq->stack_max);
776  }
777 
778  if (cref) {
779  th->cfp->ep[-1] = (VALUE)cref;
780  }
781 
782  ret = vm_exec(th);
783 
784  if (me) {
785  /* bmethod */
786  EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->klass, ret);
788  }
789 
790  return ret;
791  }
792  else {
793  return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
794  }
795 }
796 
797 static inline const rb_block_t *
799 {
800  const rb_block_t *blockptr = VM_CF_BLOCK_PTR(th->cfp);
801 
802  if (blockptr == 0) {
803  rb_vm_localjump_error("no block given", Qnil, 0);
804  }
805 
806  return blockptr;
807 }
808 
809 static inline VALUE
810 vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref)
811 {
812  const rb_block_t *blockptr = check_block(th);
813  return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref,
814  blockptr->klass);
815 }
816 
817 static inline VALUE
818 vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
819 {
820  const rb_block_t *blockptr = check_block(th);
821  return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0,
822  blockptr->klass);
823 }
824 
825 static inline VALUE
826 vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, const rb_block_t *blockargptr)
827 {
828  const rb_block_t *blockptr = check_block(th);
829  return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0,
830  blockptr->klass);
831 }
832 
833 static VALUE
834 vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class,
835  int argc, const VALUE *argv, const rb_block_t *blockptr)
836 {
837  VALUE val = Qundef;
838  int state;
839  volatile int stored_safe = th->safe_level;
840 
841  TH_PUSH_TAG(th);
842  if ((state = EXEC_TAG()) == 0) {
843  if (!proc->is_from_method) {
844  th->safe_level = proc->safe_level;
845  }
846  val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0,
847  defined_class);
848  }
849  TH_POP_TAG();
850 
851  if (!proc->is_from_method) {
852  th->safe_level = stored_safe;
853  }
854 
855  if (state) {
856  JUMP_TAG(state);
857  }
858  return val;
859 }
860 
861 VALUE
863  int argc, const VALUE *argv, const rb_block_t *blockptr)
864 {
865  return vm_invoke_proc(th, proc, proc->block.self, proc->block.klass,
866  argc, argv, blockptr);
867 }
868 
869 /* special variable */
870 
871 static rb_control_frame_t *
873 {
874  while (cfp->pc == 0) {
877  return 0;
878  }
879  }
880  return cfp;
881 }
882 
883 static VALUE
885 {
886  cfp = vm_normal_frame(th, cfp);
887  return lep_svar_get(th, cfp ? VM_CF_LEP(cfp) : 0, key);
888 }
889 
890 static void
892 {
893  cfp = vm_normal_frame(th, cfp);
894  lep_svar_set(th, cfp ? VM_CF_LEP(cfp) : 0, key, val);
895 }
896 
897 static VALUE
899 {
900  rb_thread_t *th = GET_THREAD();
901  return vm_cfp_svar_get(th, th->cfp, key);
902 }
903 
904 static void
906 {
907  rb_thread_t *th = GET_THREAD();
908  vm_cfp_svar_set(th, th->cfp, key, val);
909 }
910 
911 VALUE
913 {
914  return vm_svar_get(1);
915 }
916 
917 void
919 {
920  vm_svar_set(1, val);
921 }
922 
923 VALUE
925 {
926  return vm_svar_get(0);
927 }
928 
929 void
931 {
932  vm_svar_set(0, val);
933 }
934 
935 /* misc */
936 
937 VALUE
939 {
940  rb_thread_t *th = GET_THREAD();
942 
943  if (cfp) {
944  return cfp->iseq->location.path;
945  }
946  else {
947  return Qnil;
948  }
949 }
950 
951 const char *
953 {
954  rb_thread_t *th = GET_THREAD();
956 
957  if (cfp) {
958  return RSTRING_PTR(cfp->iseq->location.path);
959  }
960  else {
961  return 0;
962  }
963 }
964 
965 int
967 {
968  rb_thread_t *th = GET_THREAD();
970 
971  if (cfp) {
972  return rb_vm_get_sourceline(cfp);
973  }
974  else {
975  return 0;
976  }
977 }
978 
979 NODE *
981 {
982  rb_thread_t *th = GET_THREAD();
984 
985  if (cfp == 0) {
986  return NULL;
987  }
988  return rb_vm_get_cref(cfp->iseq, cfp->ep);
989 }
990 
991 NODE *
993 {
994  rb_thread_t *th = GET_THREAD();
996  if (cfp->self != self) return NULL;
997  return rb_vm_get_cref(cfp->iseq, cfp->ep);
998 }
999 
1000 #if 0
1001 void
1002 debug_cref(NODE *cref)
1003 {
1004  while (cref) {
1005  dp(cref->nd_clss);
1006  printf("%ld\n", cref->nd_visi);
1007  cref = cref->nd_next;
1008  }
1009 }
1010 #endif
1011 
1012 VALUE
1014 {
1015  rb_thread_t *th = GET_THREAD();
1017 
1018  if (cfp == 0) {
1019  rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread");
1020  }
1021  return vm_get_cbase(cfp->iseq, cfp->ep);
1022 }
1023 
1024 /* jump */
1025 
1026 static VALUE
1027 make_localjump_error(const char *mesg, VALUE value, int reason)
1028 {
1029  extern VALUE rb_eLocalJumpError;
1030  VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
1031  ID id;
1032 
1033  switch (reason) {
1034  case TAG_BREAK:
1035  CONST_ID(id, "break");
1036  break;
1037  case TAG_REDO:
1038  CONST_ID(id, "redo");
1039  break;
1040  case TAG_RETRY:
1041  CONST_ID(id, "retry");
1042  break;
1043  case TAG_NEXT:
1044  CONST_ID(id, "next");
1045  break;
1046  case TAG_RETURN:
1047  CONST_ID(id, "return");
1048  break;
1049  default:
1050  CONST_ID(id, "noreason");
1051  break;
1052  }
1053  rb_iv_set(exc, "@exit_value", value);
1054  rb_iv_set(exc, "@reason", ID2SYM(id));
1055  return exc;
1056 }
1057 
1058 void
1059 rb_vm_localjump_error(const char *mesg, VALUE value, int reason)
1060 {
1061  VALUE exc = make_localjump_error(mesg, value, reason);
1062  rb_exc_raise(exc);
1063 }
1064 
1065 VALUE
1067 {
1068  VALUE result = Qnil;
1069 
1070  if (val == Qundef) {
1071  val = GET_THREAD()->tag->retval;
1072  }
1073  switch (state) {
1074  case 0:
1075  break;
1076  case TAG_RETURN:
1077  result = make_localjump_error("unexpected return", val, state);
1078  break;
1079  case TAG_BREAK:
1080  result = make_localjump_error("unexpected break", val, state);
1081  break;
1082  case TAG_NEXT:
1083  result = make_localjump_error("unexpected next", val, state);
1084  break;
1085  case TAG_REDO:
1086  result = make_localjump_error("unexpected redo", Qnil, state);
1087  break;
1088  case TAG_RETRY:
1089  result = make_localjump_error("retry outside of rescue clause", Qnil, state);
1090  break;
1091  default:
1092  break;
1093  }
1094  return result;
1095 }
1096 
1097 void
1099 {
1101  if (!NIL_P(exc)) rb_exc_raise(exc);
1102  JUMP_TAG(state);
1103 }
1104 
1105 NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val));
1106 
1107 static void
1109 {
1110  rb_control_frame_t *cfp = th->cfp;
1111  VALUE *ep = VM_CF_PREV_EP(cfp);
1112 
1113  th->state = TAG_BREAK;
1114  th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)ep, TAG_BREAK);
1115  TH_JUMP_TAG(th, TAG_BREAK);
1116 }
1117 
1118 void
1120 {
1122 }
1123 
1124 void
1126 {
1127  vm_iter_break(GET_THREAD(), val);
1128 }
1129 
1130 /* optimization: redefine management */
1131 
1133 
1134 static int
1136 {
1137  if (klass == rb_cFixnum) return FIXNUM_REDEFINED_OP_FLAG;
1138  if (klass == rb_cFloat) return FLOAT_REDEFINED_OP_FLAG;
1139  if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG;
1140  if (klass == rb_cArray) return ARRAY_REDEFINED_OP_FLAG;
1141  if (klass == rb_cHash) return HASH_REDEFINED_OP_FLAG;
1142  if (klass == rb_cBignum) return BIGNUM_REDEFINED_OP_FLAG;
1143  if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG;
1144  if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG;
1145  if (klass == rb_cRegexp) return REGEXP_REDEFINED_OP_FLAG;
1146  return 0;
1147 }
1148 
1149 static void
1151 {
1152  st_data_t bop;
1153  if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) {
1154  if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
1155  int flag = vm_redefinition_check_flag(klass);
1156 
1157  ruby_vm_redefined_flag[bop] |= flag;
1158  }
1159  }
1160 }
1161 
1162 static int
1164 {
1165  ID mid = (ID)key;
1166  rb_method_entry_t *me = (rb_method_entry_t *)value;
1167  VALUE klass = (VALUE)data;
1168  rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL);
1169 
1170  if (newme != me)
1172  return ST_CONTINUE;
1173 }
1174 
1175 void
1177 {
1178  if (!vm_redefinition_check_flag(klass)) return;
1180  (st_data_t)klass);
1181 }
1182 
1183 static void
1184 add_opt_method(VALUE klass, ID mid, VALUE bop)
1185 {
1186  rb_method_entry_t *me;
1187  if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) && me->def &&
1188  me->def->type == VM_METHOD_TYPE_CFUNC) {
1189  st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
1190  }
1191  else {
1192  rb_bug("undefined optimized method: %s", rb_id2name(mid));
1193  }
1194 }
1195 
1196 static void
1198 {
1199  ID mid;
1200  VALUE bop;
1201 
1202  vm_opt_method_table = st_init_numtable();
1203 
1204 #define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)
1205 #define C(k) add_opt_method(rb_c##k, mid, bop)
1206  OP(PLUS, PLUS), (C(Fixnum), C(Float), C(String), C(Array));
1207  OP(MINUS, MINUS), (C(Fixnum), C(Float));
1208  OP(MULT, MULT), (C(Fixnum), C(Float));
1209  OP(DIV, DIV), (C(Fixnum), C(Float));
1210  OP(MOD, MOD), (C(Fixnum), C(Float));
1211  OP(Eq, EQ), (C(Fixnum), C(Float), C(String));
1212  OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String));
1213  OP(LT, LT), (C(Fixnum), C(Float));
1214  OP(LE, LE), (C(Fixnum), C(Float));
1215  OP(GT, GT), (C(Fixnum), C(Float));
1216  OP(GE, GE), (C(Fixnum), C(Float));
1217  OP(LTLT, LTLT), (C(String), C(Array));
1218  OP(AREF, AREF), (C(Array), C(Hash));
1219  OP(ASET, ASET), (C(Array), C(Hash));
1220  OP(Length, LENGTH), (C(Array), C(String), C(Hash));
1221  OP(Size, SIZE), (C(Array), C(String), C(Hash));
1222  OP(EmptyP, EMPTY_P), (C(Array), C(String), C(Hash));
1223  OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
1224  OP(EqTilde, MATCH), (C(Regexp), C(String));
1225  OP(Freeze, FREEZE), (C(String));
1226 #undef C
1227 #undef OP
1228 }
1229 
1230 /* for vm development */
1231 
1232 #if VMDEBUG
1233 static const char *
1234 vm_frametype_name(const rb_control_frame_t *cfp)
1235 {
1236  switch (VM_FRAME_TYPE(cfp)) {
1237  case VM_FRAME_MAGIC_METHOD: return "method";
1238  case VM_FRAME_MAGIC_BLOCK: return "block";
1239  case VM_FRAME_MAGIC_CLASS: return "class";
1240  case VM_FRAME_MAGIC_TOP: return "top";
1241  case VM_FRAME_MAGIC_CFUNC: return "cfunc";
1242  case VM_FRAME_MAGIC_PROC: return "proc";
1243  case VM_FRAME_MAGIC_IFUNC: return "ifunc";
1244  case VM_FRAME_MAGIC_EVAL: return "eval";
1245  case VM_FRAME_MAGIC_LAMBDA: return "lambda";
1246  case VM_FRAME_MAGIC_RESCUE: return "rescue";
1247  default:
1248  rb_bug("unknown frame");
1249  }
1250 }
1251 #endif
1252 
1253 /* evaluator body */
1254 
1255 /* finish
1256  VMe (h1) finish
1257  VM finish F1 F2
1258  cfunc finish F1 F2 C1
1259  rb_funcall finish F1 F2 C1
1260  VMe finish F1 F2 C1
1261  VM finish F1 F2 C1 F3
1262 
1263  F1 - F3 : pushed by VM
1264  C1 : pushed by send insn (CFUNC)
1265 
1266  struct CONTROL_FRAME {
1267  VALUE *pc; // cfp[0], program counter
1268  VALUE *sp; // cfp[1], stack pointer
1269  VALUE *bp; // cfp[2], base pointer
1270  rb_iseq_t *iseq; // cfp[3], iseq
1271  VALUE flag; // cfp[4], magic
1272  VALUE self; // cfp[5], self
1273  VALUE *ep; // cfp[6], env pointer
1274  rb_iseq_t * block_iseq; // cfp[7], block iseq
1275  VALUE proc; // cfp[8], always 0
1276  };
1277 
1278  struct BLOCK {
1279  VALUE self;
1280  VALUE *ep;
1281  rb_iseq_t *block_iseq;
1282  VALUE proc;
1283  };
1284 
1285  struct METHOD_CONTROL_FRAME {
1286  rb_control_frame_t frame;
1287  };
1288 
1289  struct METHOD_FRAME {
1290  VALUE arg0;
1291  ...
1292  VALUE argM;
1293  VALUE param0;
1294  ...
1295  VALUE paramN;
1296  VALUE cref;
1297  VALUE special; // lep [1]
1298  struct block_object *block_ptr | 0x01; // lep [0]
1299  };
1300 
1301  struct BLOCK_CONTROL_FRAME {
1302  rb_control_frame_t frame;
1303  };
1304 
1305  struct BLOCK_FRAME {
1306  VALUE arg0;
1307  ...
1308  VALUE argM;
1309  VALUE param0;
1310  ...
1311  VALUE paramN;
1312  VALUE cref;
1313  VALUE *(prev_ptr | 0x01); // ep[0]
1314  };
1315 
1316  struct CLASS_CONTROL_FRAME {
1317  rb_control_frame_t frame;
1318  };
1319 
1320  struct CLASS_FRAME {
1321  VALUE param0;
1322  ...
1323  VALUE paramN;
1324  VALUE cref;
1325  VALUE prev_ep; // for frame jump
1326  };
1327 
1328  struct C_METHOD_CONTROL_FRAME {
1329  VALUE *pc; // 0
1330  VALUE *sp; // stack pointer
1331  VALUE *bp; // base pointer (used in exception)
1332  rb_iseq_t *iseq; // cmi
1333  VALUE magic; // C_METHOD_FRAME
1334  VALUE self; // ?
1335  VALUE *ep; // ep == lep
1336  rb_iseq_t * block_iseq; //
1337  VALUE proc; // always 0
1338  };
1339 
1340  struct C_BLOCK_CONTROL_FRAME {
1341  VALUE *pc; // point only "finish" insn
1342  VALUE *sp; // sp
1343  rb_iseq_t *iseq; // ?
1344  VALUE magic; // C_METHOD_FRAME
1345  VALUE self; // needed?
1346  VALUE *ep; // ep
1347  rb_iseq_t * block_iseq; // 0
1348  };
1349  */
1350 
1351 
1352 static VALUE
1354 {
1355  int state;
1356  VALUE result, err;
1357  VALUE initial = 0;
1358 
1359  TH_PUSH_TAG(th);
1360  _tag.retval = Qnil;
1361  if ((state = EXEC_TAG()) == 0) {
1362  vm_loop_start:
1363  result = vm_exec_core(th, initial);
1364  if ((state = th->state) != 0) {
1365  err = result;
1366  th->state = 0;
1367  goto exception_handler;
1368  }
1369  }
1370  else {
1371  int i;
1372  struct iseq_catch_table_entry *entry;
1373  unsigned long epc, cont_pc, cont_sp;
1374  VALUE catch_iseqval;
1375  rb_control_frame_t *cfp;
1376  VALUE type;
1377  VALUE *escape_ep;
1378 
1379  err = th->errinfo;
1380 
1381  exception_handler:
1382  cont_pc = cont_sp = catch_iseqval = 0;
1383 
1384  while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
1386  const rb_method_entry_t *me = th->cfp->me;
1389  }
1391  }
1392 
1393  cfp = th->cfp;
1394  epc = cfp->pc - cfp->iseq->iseq_encoded;
1395 
1396  escape_ep = NULL;
1397  if (state == TAG_BREAK || state == TAG_RETURN) {
1398  escape_ep = GET_THROWOBJ_CATCH_POINT(err);
1399 
1400  if (cfp->ep == escape_ep) {
1401  if (state == TAG_RETURN) {
1402  if (!VM_FRAME_TYPE_FINISH_P(cfp)) {
1403  SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->ep);
1404  SET_THROWOBJ_STATE(err, state = TAG_BREAK);
1405  }
1406  else {
1407  for (i = 0; i < cfp->iseq->catch_table_size; i++) {
1408  entry = &cfp->iseq->catch_table[i];
1409  if (entry->start < epc && entry->end >= epc) {
1410  if (entry->type == CATCH_TYPE_ENSURE) {
1411  catch_iseqval = entry->iseq;
1412  cont_pc = entry->cont;
1413  cont_sp = entry->sp;
1414  break;
1415  }
1416  }
1417  }
1418  if (!catch_iseqval) {
1419  result = GET_THROWOBJ_VAL(err);
1420  th->errinfo = Qnil;
1421 
1422  switch (VM_FRAME_TYPE(cfp)) {
1423  case VM_FRAME_MAGIC_LAMBDA:
1425  break;
1426  }
1427 
1428  vm_pop_frame(th);
1429  goto finish_vme;
1430  }
1431  }
1432  /* through */
1433  }
1434  else {
1435  /* TAG_BREAK */
1436 #if OPT_STACK_CACHING
1437  initial = (GET_THROWOBJ_VAL(err));
1438 #else
1439  *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
1440 #endif
1441  th->errinfo = Qnil;
1442  goto vm_loop_start;
1443  }
1444  }
1445  }
1446 
1447  if (state == TAG_RAISE) {
1448  for (i = 0; i < cfp->iseq->catch_table_size; i++) {
1449  entry = &cfp->iseq->catch_table[i];
1450  if (entry->start < epc && entry->end >= epc) {
1451 
1452  if (entry->type == CATCH_TYPE_RESCUE ||
1453  entry->type == CATCH_TYPE_ENSURE) {
1454  catch_iseqval = entry->iseq;
1455  cont_pc = entry->cont;
1456  cont_sp = entry->sp;
1457  break;
1458  }
1459  }
1460  }
1461  }
1462  else if (state == TAG_RETRY) {
1463  for (i = 0; i < cfp->iseq->catch_table_size; i++) {
1464  entry = &cfp->iseq->catch_table[i];
1465  if (entry->start < epc && entry->end >= epc) {
1466 
1467  if (entry->type == CATCH_TYPE_ENSURE) {
1468  catch_iseqval = entry->iseq;
1469  cont_pc = entry->cont;
1470  cont_sp = entry->sp;
1471  break;
1472  }
1473  else if (entry->type == CATCH_TYPE_RETRY) {
1474  VALUE *escape_ep;
1475  escape_ep = GET_THROWOBJ_CATCH_POINT(err);
1476  if (cfp->ep == escape_ep) {
1477  cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
1478  th->errinfo = Qnil;
1479  goto vm_loop_start;
1480  }
1481  }
1482  }
1483  }
1484  }
1485  else if (state == TAG_BREAK && ((VALUE)escape_ep & ~0x03) == 0) {
1486  type = CATCH_TYPE_BREAK;
1487 
1488  search_restart_point:
1489  for (i = 0; i < cfp->iseq->catch_table_size; i++) {
1490  entry = &cfp->iseq->catch_table[i];
1491 
1492  if (entry->start < epc && entry->end >= epc) {
1493  if (entry->type == CATCH_TYPE_ENSURE) {
1494  catch_iseqval = entry->iseq;
1495  cont_pc = entry->cont;
1496  cont_sp = entry->sp;
1497  break;
1498  }
1499  else if (entry->type == type) {
1500  cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
1501  cfp->sp = vm_base_ptr(cfp) + entry->sp;
1502 
1503  if (state != TAG_REDO) {
1504 #if OPT_STACK_CACHING
1505  initial = (GET_THROWOBJ_VAL(err));
1506 #else
1507  *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
1508 #endif
1509  }
1510  th->errinfo = Qnil;
1511  th->state = 0;
1512  goto vm_loop_start;
1513  }
1514  }
1515  }
1516  }
1517  else if (state == TAG_REDO) {
1518  type = CATCH_TYPE_REDO;
1519  goto search_restart_point;
1520  }
1521  else if (state == TAG_NEXT) {
1522  type = CATCH_TYPE_NEXT;
1523  goto search_restart_point;
1524  }
1525  else {
1526  for (i = 0; i < cfp->iseq->catch_table_size; i++) {
1527  entry = &cfp->iseq->catch_table[i];
1528  if (entry->start < epc && entry->end >= epc) {
1529 
1530  if (entry->type == CATCH_TYPE_ENSURE) {
1531  catch_iseqval = entry->iseq;
1532  cont_pc = entry->cont;
1533  cont_sp = entry->sp;
1534  break;
1535  }
1536  }
1537  }
1538  }
1539 
1540  if (catch_iseqval != 0) {
1541  /* found catch table */
1542  rb_iseq_t *catch_iseq;
1543 
1544  /* enter catch scope */
1545  GetISeqPtr(catch_iseqval, catch_iseq);
1546  cfp->sp = vm_base_ptr(cfp) + cont_sp;
1547  cfp->pc = cfp->iseq->iseq_encoded + cont_pc;
1548 
1549  /* push block frame */
1550  cfp->sp[0] = err;
1551  vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
1552  cfp->self, cfp->klass,
1553  VM_ENVVAL_PREV_EP_PTR(cfp->ep),
1554  catch_iseq->iseq_encoded,
1555  cfp->sp + 1 /* push value */,
1556  catch_iseq->local_size - 1,
1557  cfp->me, catch_iseq->stack_max);
1558 
1559  state = 0;
1560  th->state = 0;
1561  th->errinfo = Qnil;
1562  goto vm_loop_start;
1563  }
1564  else {
1565  /* skip frame */
1566 
1567  switch (VM_FRAME_TYPE(th->cfp)) {
1568  case VM_FRAME_MAGIC_METHOD:
1571  break;
1572  case VM_FRAME_MAGIC_BLOCK:
1573  case VM_FRAME_MAGIC_LAMBDA:
1574  if (VM_FRAME_TYPE_BMETHOD_P(th->cfp)) {
1575  EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
1577  }
1578  else {
1580  }
1581  break;
1582  case VM_FRAME_MAGIC_CLASS:
1584  break;
1585  }
1586 
1587  if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
1588  vm_pop_frame(th);
1589  th->errinfo = err;
1590  TH_POP_TAG2();
1591  JUMP_TAG(state);
1592  }
1593  else {
1595  goto exception_handler;
1596  }
1597  }
1598  }
1599  finish_vme:
1600  TH_POP_TAG();
1601  return result;
1602 }
1603 
1604 /* misc */
1605 
1606 VALUE
1608 {
1609  rb_thread_t *th = GET_THREAD();
1610  VALUE val;
1611 
1612  vm_set_top_stack(th, iseqval);
1613 
1614  val = vm_exec(th);
1615  RB_GC_GUARD(iseqval); /* prohibit tail call optimization */
1616  return val;
1617 }
1618 
1619 VALUE
1621 {
1622  rb_thread_t *th = GET_THREAD();
1623  VALUE val;
1624 
1625  vm_set_main_stack(th, iseqval);
1626 
1627  val = vm_exec(th);
1628  RB_GC_GUARD(iseqval); /* prohibit tail call optimization */
1629  return val;
1630 }
1631 
1632 int
1634 {
1635  rb_iseq_t *iseq = cfp->iseq;
1636  if (!iseq && cfp->me) {
1637  if (idp) *idp = cfp->me->def->original_id;
1638  if (klassp) *klassp = cfp->me->klass;
1639  return 1;
1640  }
1641  while (iseq) {
1642  if (RUBY_VM_IFUNC_P(iseq)) {
1643  if (idp) *idp = idIFUNC;
1644  if (klassp) *klassp = 0;
1645  return 1;
1646  }
1647  if (iseq->defined_method_id) {
1648  if (idp) *idp = iseq->defined_method_id;
1649  if (klassp) *klassp = iseq->klass;
1650  return 1;
1651  }
1652  if (iseq->local_iseq == iseq) {
1653  break;
1654  }
1655  iseq = iseq->parent_iseq;
1656  }
1657  return 0;
1658 }
1659 
1660 int
1662 {
1663  return rb_vm_control_frame_id_and_class(th->cfp, idp, klassp);
1664 }
1665 
1666 int
1668 {
1669  return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp);
1670 }
1671 
1672 VALUE
1674 {
1675  const rb_control_frame_t *cfp = th->cfp;
1676  VALUE str = Qnil;
1677 
1678  if (cfp->iseq != 0) {
1679  if (cfp->pc != 0) {
1680  rb_iseq_t *iseq = cfp->iseq;
1681  int line_no = rb_vm_get_sourceline(cfp);
1682  char *file = RSTRING_PTR(iseq->location.path);
1683  str = rb_sprintf("%s:%d:in `%s'",
1684  file, line_no, RSTRING_PTR(iseq->location.label));
1685  }
1686  }
1687  else if (cfp->me->def->original_id) {
1688  str = rb_sprintf("`%s#%s' (cfunc)",
1689  rb_class2name(cfp->me->klass),
1690  rb_id2name(cfp->me->def->original_id));
1691  }
1692 
1693  return str;
1694 }
1695 
1696 VALUE
1698  const rb_block_t *blockptr, VALUE filename)
1699 {
1700  rb_thread_t *th = GET_THREAD();
1701  const rb_control_frame_t *reg_cfp = th->cfp;
1702  volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
1703  VALUE val;
1704 
1706  recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0, 0);
1707 
1708  val = (*func)(arg);
1709 
1710  vm_pop_frame(th);
1711  return val;
1712 }
1713 
1714 /* vm */
1715 
1716 static int
1718 {
1719  VALUE thval = (VALUE)key;
1720  rb_gc_mark(thval);
1721  return ST_CONTINUE;
1722 }
1723 
1725 
1726 void
1727 rb_vm_mark(void *ptr)
1728 {
1729  int i;
1730 
1731  RUBY_MARK_ENTER("vm");
1732  RUBY_GC_INFO("-------------------------------------------------\n");
1733  if (ptr) {
1734  rb_vm_t *vm = ptr;
1735  if (vm->living_threads) {
1737  }
1750 
1751  if (vm->loading_table) {
1753  }
1754 
1756 
1757  for (i = 0; i < RUBY_NSIG; i++) {
1758  if (vm->trap_list[i].cmd)
1759  rb_gc_mark(vm->trap_list[i].cmd);
1760  }
1761  if (vm->defined_strings) {
1763  }
1764  }
1765 
1766  RUBY_MARK_LEAVE("vm");
1767 }
1768 
1769 
1770 int
1772 {
1773  rb_vm_t *vm = GET_VM();
1774  if (vm->defined_module_hash) {
1775  rb_hash_aset(vm->defined_module_hash, ID2SYM(id), module);
1776  }
1777  return TRUE;
1778 }
1779 
1780 #define vm_free 0
1781 
1782 int
1784 {
1785  RUBY_FREE_ENTER("vm");
1786  if (vm) {
1787  rb_thread_t *th = vm->main_thread;
1788 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
1789  struct rb_objspace *objspace = vm->objspace;
1790 #endif
1792  vm->main_thread = 0;
1793  if (th) {
1795  thread_free(th);
1796  }
1797  if (vm->living_threads) {
1799  vm->living_threads = 0;
1800  }
1802  rb_vm_gvl_destroy(vm);
1803 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
1804  if (objspace) {
1805  rb_objspace_free(objspace);
1806  }
1807 #endif
1808  /* after freeing objspace, you *can't* use ruby_xfree() */
1809  ruby_mimfree(vm);
1810  ruby_current_vm = 0;
1811  }
1812  RUBY_FREE_LEAVE("vm");
1813  return 0;
1814 }
1815 
1816 static size_t
1817 vm_memsize(const void *ptr)
1818 {
1819  if (ptr) {
1820  const rb_vm_t *vmobj = ptr;
1821  size_t size = sizeof(rb_vm_t);
1822  if (vmobj->living_threads) {
1823  size += st_memsize(vmobj->living_threads);
1824  }
1825  if (vmobj->defined_strings) {
1826  size += DEFINED_EXPR * sizeof(VALUE);
1827  }
1828  return size;
1829  }
1830  else {
1831  return 0;
1832  }
1833 }
1834 
1836  "VM",
1839 };
1840 
1841 
1842 static VALUE
1844 {
1845  rb_vm_t *vm = GET_VM();
1846  VALUE result = rb_hash_new();
1847 #define SET(name) rb_hash_aset(result, ID2SYM(rb_intern(#name)), SIZET2NUM(vm->default_params.name));
1848  SET(thread_vm_stack_size);
1849  SET(thread_machine_stack_size);
1850  SET(fiber_vm_stack_size);
1851  SET(fiber_machine_stack_size);
1852 #undef SET
1853  rb_obj_freeze(result);
1854  return result;
1855 }
1856 
1857 static size_t
1858 get_param(const char *name, size_t default_value, size_t min_value)
1859 {
1860  const char *envval;
1861  size_t result = default_value;
1862  if ((envval = getenv(name)) != 0) {
1863  long val = atol(envval);
1864  if (val < (long)min_value) {
1865  val = (long)min_value;
1866  }
1867  result = (size_t)(((val -1 + RUBY_VM_SIZE_ALIGN) / RUBY_VM_SIZE_ALIGN) * RUBY_VM_SIZE_ALIGN);
1868  }
1869  if (0) fprintf(stderr, "%s: %"PRIdSIZE"\n", name, result); /* debug print */
1870 
1871  return result;
1872 }
1873 
1874 static void
1876 {
1877 #ifdef PTHREAD_STACK_MIN
1878  size_t size = *sizep;
1879 #endif
1880 
1881 #ifdef __SYMBIAN32__
1882  *sizep = 64 * 1024; /* 64KB: Let's be slightly more frugal on mobile platform */
1883 #endif
1884 
1885 #ifdef PTHREAD_STACK_MIN
1886  if (size < PTHREAD_STACK_MIN) {
1887  *sizep = PTHREAD_STACK_MIN * 2;
1888  }
1889 #endif
1890 }
1891 
1892 static void
1894 {
1896  get_param("RUBY_THREAD_VM_STACK_SIZE",
1899 
1901  get_param("RUBY_THREAD_MACHINE_STACK_SIZE",
1904 
1906  get_param("RUBY_FIBER_VM_STACK_SIZE",
1909 
1911  get_param("RUBY_FIBER_MACHINE_STACK_SIZE",
1914 
1915  /* environment dependent check */
1918 }
1919 
1920 static void
1922 {
1923  MEMZERO(vm, rb_vm_t, 1);
1924  vm->src_encoding_index = -1;
1925  vm->at_exit.basic.flags = (T_ARRAY | RARRAY_EMBED_FLAG) & ~RARRAY_EMBED_LEN_MASK; /* len set 0 */
1926  rb_obj_hide((VALUE)&vm->at_exit);
1927 
1929 }
1930 
1931 /* Thread */
1932 
1933 #define USE_THREAD_DATA_RECYCLE 1
1934 
1935 #if USE_THREAD_DATA_RECYCLE
1936 #define RECYCLE_MAX 64
1939 
1940 static VALUE *
1942 {
1943  if (thread_recycle_stack_count) {
1944  /* TODO: check stack size if stack sizes are variable */
1945  return thread_recycle_stack_slot[--thread_recycle_stack_count];
1946  }
1947  else {
1948  return ALLOC_N(VALUE, size);
1949  }
1950 }
1951 
1952 #else
1953 #define thread_recycle_stack(size) ALLOC_N(VALUE, (size))
1954 #endif
1955 
1956 void
1958 {
1959 #if USE_THREAD_DATA_RECYCLE
1960  if (thread_recycle_stack_count < RECYCLE_MAX) {
1961  thread_recycle_stack_slot[thread_recycle_stack_count++] = stack;
1962  return;
1963  }
1964 #endif
1965  ruby_xfree(stack);
1966 }
1967 
1968 #ifdef USE_THREAD_RECYCLE
1969 static rb_thread_t *
1970 thread_recycle_struct(void)
1971 {
1972  void *p = ALLOC_N(rb_thread_t, 1);
1973  memset(p, 0, sizeof(rb_thread_t));
1974  return p;
1975 }
1976 #endif
1977 
1978 void
1979 rb_thread_mark(void *ptr)
1980 {
1981  rb_thread_t *th = NULL;
1982  RUBY_MARK_ENTER("thread");
1983  if (ptr) {
1984  th = ptr;
1985  if (th->stack) {
1986  VALUE *p = th->stack;
1987  VALUE *sp = th->cfp->sp;
1988  rb_control_frame_t *cfp = th->cfp;
1989  rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
1990 
1991  while (p < sp) {
1992  rb_gc_mark(*p++);
1993  }
1995 
1996  while (cfp != limit_cfp) {
1997  rb_iseq_t *iseq = cfp->iseq;
1998  rb_gc_mark(cfp->proc);
1999  rb_gc_mark(cfp->self);
2000  rb_gc_mark(cfp->klass);
2001  if (iseq) {
2002  rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq);
2003  }
2004  if (cfp->me) {
2005  /* TODO: marking `me' can be more sophisticated way */
2006  ((rb_method_entry_t *)cfp->me)->mark = 1;
2007  rb_mark_method_entry(cfp->me);
2008  }
2009  cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
2010  }
2011  }
2012 
2013  /* mark ruby objects */
2016 
2029 
2031 
2033 
2034  if (GET_THREAD() != th && th->machine.stack_start && th->machine.stack_end) {
2037  (VALUE *)(&th->machine.regs) +
2038  sizeof(th->machine.regs) / sizeof(VALUE));
2039  }
2040 
2042  }
2043 
2044  RUBY_MARK_LEAVE("thread");
2045 }
2046 
2047 static void
2048 thread_free(void *ptr)
2049 {
2050  rb_thread_t *th;
2051  RUBY_FREE_ENTER("thread");
2052 
2053  if (ptr) {
2054  th = ptr;
2055 
2056  if (!th->root_fiber) {
2058  }
2059 
2060  if (th->locking_mutex != Qfalse) {
2061  rb_bug("thread_free: locking_mutex must be NULL (%p:%p)", (void *)th, (void *)th->locking_mutex);
2062  }
2063  if (th->keeping_mutexes != NULL) {
2064  rb_bug("thread_free: keeping_mutexes must be NULL (%p:%p)", (void *)th, (void *)th->keeping_mutexes);
2065  }
2066 
2067  if (th->local_storage) {
2069  }
2070 
2071  if (th->vm && th->vm->main_thread == th) {
2072  RUBY_GC_INFO("main thread\n");
2073  }
2074  else {
2075 #ifdef USE_SIGALTSTACK
2076  if (th->altstack) {
2077  free(th->altstack);
2078  }
2079 #endif
2080  ruby_xfree(ptr);
2081  }
2082  if (ruby_current_thread == th)
2083  ruby_current_thread = NULL;
2084  }
2085  RUBY_FREE_LEAVE("thread");
2086 }
2087 
2088 static size_t
2089 thread_memsize(const void *ptr)
2090 {
2091  if (ptr) {
2092  const rb_thread_t *th = ptr;
2093  size_t size = sizeof(rb_thread_t);
2094 
2095  if (!th->root_fiber) {
2096  size += th->stack_size * sizeof(VALUE);
2097  }
2098  if (th->local_storage) {
2099  size += st_memsize(th->local_storage);
2100  }
2101  return size;
2102  }
2103  else {
2104  return 0;
2105  }
2106 }
2107 
2108 #define thread_data_type ruby_threadptr_data_type
2110  "VM/thread",
2111  {
2113  thread_free,
2115  },
2117 };
2118 
2119 VALUE
2121 {
2123  return Qtrue;
2124  }
2125  else {
2126  return Qfalse;
2127  }
2128 }
2129 
2130 static VALUE
2132 {
2133  VALUE volatile obj;
2134 #ifdef USE_THREAD_RECYCLE
2135  rb_thread_t *th = thread_recycle_struct();
2136  obj = TypedData_Wrap_Struct(klass, &thread_data_type, th);
2137 #else
2138  rb_thread_t *th;
2140 #endif
2141  return obj;
2142 }
2143 
2144 static void
2146 {
2147  th->self = self;
2148 
2149  /* allocate thread stack */
2150 #ifdef USE_SIGALTSTACK
2151  /* altstack of main thread is reallocated in another place */
2152  th->altstack = malloc(rb_sigaltstack_size());
2153 #endif
2154  /* th->stack_size is word number.
2155  * th->vm->default_params.thread_vm_stack_size is byte size.
2156  */
2157  th->stack_size = th->vm->default_params.thread_vm_stack_size / sizeof(VALUE);
2159 
2160  th->cfp = (void *)(th->stack + th->stack_size);
2161 
2162  vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
2163  Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0, 0);
2164 
2165  th->status = THREAD_RUNNABLE;
2166  th->errinfo = Qnil;
2167  th->last_status = Qnil;
2168  th->waiting_fd = -1;
2169  th->root_svar = Qnil;
2170 
2171 #if OPT_CALL_THREADED_CODE
2172  th->retval = Qundef;
2173 #endif
2174 }
2175 
2176 static VALUE
2178 {
2179  rb_thread_t *th;
2180  rb_vm_t *vm = GET_THREAD()->vm;
2181  GetThreadPtr(self, th);
2182 
2183  th->vm = vm;
2184  th_init(th, self);
2185  rb_ivar_set(self, rb_intern("locals"), rb_hash_new());
2186 
2187  th->top_wrapper = 0;
2188  th->top_self = rb_vm_top_self();
2189  th->root_svar = Qnil;
2190  return self;
2191 }
2192 
2193 VALUE
2195 {
2196  VALUE self = thread_alloc(klass);
2197  ruby_thread_init(self);
2198  return self;
2199 }
2200 
2201 static void
2203  rb_num_t is_singleton, NODE *cref)
2204 {
2205  VALUE klass = cref->nd_clss;
2206  int noex = (int)cref->nd_visi;
2207  rb_iseq_t *miseq;
2208  GetISeqPtr(iseqval, miseq);
2209 
2210  if (miseq->klass) {
2211  RB_GC_GUARD(iseqval) = rb_iseq_clone(iseqval, 0);
2212  GetISeqPtr(iseqval, miseq);
2213  }
2214 
2215  if (NIL_P(klass)) {
2216  rb_raise(rb_eTypeError, "no class/module to add method");
2217  }
2218 
2219  if (is_singleton) {
2220  klass = rb_singleton_class(obj); /* class and frozen checked in this API */
2221  noex = NOEX_PUBLIC;
2222  }
2223 
2224  /* dup */
2225  COPY_CREF(miseq->cref_stack, cref);
2226  miseq->cref_stack->nd_visi = NOEX_PUBLIC;
2227  RB_OBJ_WRITE(miseq->self, &miseq->klass, klass);
2228  miseq->defined_method_id = id;
2229  rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
2230 
2231  if (!is_singleton && noex == NOEX_MODFUNC) {
2232  klass = rb_singleton_class(klass);
2233  rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
2234  }
2235 }
2236 
2237 #define REWIND_CFP(expr) do { \
2238  rb_thread_t *th__ = GET_THREAD(); \
2239  th__->cfp++; expr; th__->cfp--; \
2240 } while (0)
2241 
2242 static VALUE
2244 {
2245  REWIND_CFP({
2246  vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
2247  });
2248  return sym;
2249 }
2250 
2251 static VALUE
2253 {
2254  REWIND_CFP({
2255  vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
2256  });
2257  return sym;
2258 }
2259 
2260 static VALUE
2262 {
2263  REWIND_CFP({
2264  rb_alias(cbase, SYM2ID(sym1), SYM2ID(sym2));
2265  });
2266  return Qnil;
2267 }
2268 
2269 static VALUE
2271 {
2272  REWIND_CFP({
2273  rb_alias_variable(SYM2ID(sym1), SYM2ID(sym2));
2274  });
2275  return Qnil;
2276 }
2277 
2278 static VALUE
2280 {
2281  REWIND_CFP({
2282  rb_undef(cbase, SYM2ID(sym));
2284  });
2285  return Qnil;
2286 }
2287 
2288 static VALUE
2290 {
2292  return Qnil;
2293 }
2294 
2296 static VALUE core_hash_from_ary(VALUE ary);
2297 static VALUE core_hash_merge_kwd(int argc, VALUE *argv);
2298 
2299 static VALUE
2301 {
2302  long i;
2303 
2304  assert(argc % 2 == 0);
2305  for (i=0; i<argc; i+=2) {
2306  rb_hash_aset(hash, argv[i], argv[i+1]);
2307  }
2308  return hash;
2309 }
2310 
2311 static VALUE
2313 {
2314  VALUE hash;
2315  REWIND_CFP(hash = core_hash_from_ary(ary));
2316  return hash;
2317 }
2318 
2319 static VALUE
2321 {
2322  VALUE hash = rb_hash_new();
2323 
2326  }
2327 
2328  return core_hash_merge_ary(hash, ary);
2329 }
2330 
2331 static VALUE
2333 {
2334  REWIND_CFP(core_hash_merge_ary(hash, ary));
2335  return hash;
2336 }
2337 
2338 static VALUE
2340 {
2341  core_hash_merge(hash, RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
2342  return hash;
2343 }
2344 
2345 static VALUE
2347 {
2348  VALUE hash = argv[0];
2349 
2350  REWIND_CFP(core_hash_merge(hash, argc-1, argv+1));
2351 
2352  return hash;
2353 }
2354 
2355 static int
2356 kwmerge_ii(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
2357 {
2358  if (existing) return ST_STOP;
2359  *value = arg;
2360  return ST_CONTINUE;
2361 }
2362 
2363 static int
2365 {
2366  if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL);
2367  if (st_update(RHASH_TBL_RAW(hash), key, kwmerge_ii, (st_data_t)value) == 0) { /* !existing */
2368  RB_OBJ_WRITTEN(hash, Qundef, value);
2369  }
2370  return ST_CONTINUE;
2371 }
2372 
2373 static int
2375 {
2376  if (!SYMBOL_P(key)) Check_Type(key, T_SYMBOL);
2377  return ST_CONTINUE;
2378 }
2379 
2380 static VALUE
2382 {
2383  VALUE hash;
2384  REWIND_CFP(hash = core_hash_merge_kwd(argc, argv));
2385  return hash;
2386 }
2387 
2388 static VALUE
2390 {
2391  VALUE hash, kw;
2392  rb_check_arity(argc, 1, 2);
2393  hash = argv[0];
2394  kw = argv[argc-1];
2395  kw = rb_convert_type(kw, T_HASH, "Hash", "to_hash");
2396  if (argc < 2) hash = kw;
2397  rb_hash_foreach(kw, argc < 2 ? kwcheck_i : kwmerge_i, hash);
2398  return hash;
2399 }
2400 
2401 extern VALUE *rb_gc_stack_start;
2402 extern size_t rb_gc_stack_maxsize;
2403 #ifdef __ia64
2404 extern VALUE *rb_gc_register_stack_start;
2405 #endif
2406 
2407 /* debug functions */
2408 
2409 /* :nodoc: */
2410 static VALUE
2411 sdr(void)
2412 {
2413  rb_vm_bugreport();
2414  return Qnil;
2415 }
2416 
2417 /* :nodoc: */
2418 static VALUE
2419 nsdr(void)
2420 {
2421  VALUE ary = rb_ary_new();
2422 #if HAVE_BACKTRACE
2423 #include <execinfo.h>
2424 #define MAX_NATIVE_TRACE 1024
2425  static void *trace[MAX_NATIVE_TRACE];
2426  int n = backtrace(trace, MAX_NATIVE_TRACE);
2427  char **syms = backtrace_symbols(trace, n);
2428  int i;
2429 
2430  if (syms == 0) {
2431  rb_memerror();
2432  }
2433 
2434  for (i=0; i<n; i++) {
2435  rb_ary_push(ary, rb_str_new2(syms[i]));
2436  }
2437  free(syms); /* OK */
2438 #endif
2439  return ary;
2440 }
2441 
2442 #if VM_COLLECT_USAGE_DETAILS
2443 static VALUE usage_analysis_insn_stop(VALUE self);
2444 static VALUE usage_analysis_operand_stop(VALUE self);
2445 static VALUE usage_analysis_register_stop(VALUE self);
2446 #endif
2447 
2448 void
2449 Init_VM(void)
2450 {
2451  VALUE opts;
2452  VALUE klass;
2453  VALUE fcore;
2454 
2455  /* ::RubyVM */
2456  rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);
2460 
2461  /* FrozenCore (hidden) */
2462  fcore = rb_class_new(rb_cBasicObject);
2463  RBASIC(fcore)->flags = T_ICLASS;
2464  klass = rb_singleton_class(fcore);
2475  rb_define_method_id(klass, idProc, rb_block_proc, 0);
2476  rb_define_method_id(klass, idLambda, rb_block_lambda, 0);
2477  rb_obj_freeze(fcore);
2478  RBASIC_CLEAR_CLASS(klass);
2479  RCLASS_SET_SUPER(klass, 0);
2480  rb_obj_freeze(klass);
2482  rb_mRubyVMFrozenCore = fcore;
2483 
2484  /* ::RubyVM::Env */
2487  rb_undef_method(CLASS_OF(rb_cEnv), "new");
2488 
2489  /*
2490  * Document-class: Thread
2491  *
2492  * Threads are the Ruby implementation for a concurrent programming model.
2493  *
2494  * Programs that require multiple threads of execution are a perfect
2495  * candidate for Ruby's Thread class.
2496  *
2497  * For example, we can create a new thread separate from the main thread's
2498  * execution using ::new.
2499  *
2500  * thr = Thread.new { puts "Whats the big deal" }
2501  *
2502  * Then we are able to pause the execution of the main thread and allow
2503  * our new thread to finish, using #join:
2504  *
2505  * thr.join #=> "Whats the big deal"
2506  *
2507  * If we don't call +thr.join+ before the main thread terminates, then all
2508  * other threads including +thr+ will be killed.
2509  *
2510  * Alternatively, you can use an array for handling multiple threads at
2511  * once, like in the following example:
2512  *
2513  * threads = []
2514  * threads << Thread.new { puts "Whats the big deal" }
2515  * threads << Thread.new { 3.times { puts "Threads are fun!" } }
2516  *
2517  * After creating a few threads we wait for them all to finish
2518  * consecutively.
2519  *
2520  * threads.each { |thr| thr.join }
2521  *
2522  * === Thread initialization
2523  *
2524  * In order to create new threads, Ruby provides ::new, ::start, and
2525  * ::fork. A block must be provided with each of these methods, otherwise
2526  * a ThreadError will be raised.
2527  *
2528  * When subclassing the Thread class, the +initialize+ method of your
2529  * subclass will be ignored by ::start and ::fork. Otherwise, be sure to
2530  * call super in your +initialize+ method.
2531  *
2532  * === Thread termination
2533  *
2534  * For terminating threads, Ruby provides a variety of ways to do this.
2535  *
2536  * The class method ::kill, is meant to exit a given thread:
2537  *
2538  * thr = Thread.new { ... }
2539  * Thread.kill(thr) # sends exit() to thr
2540  *
2541  * Alternatively, you can use the instance method #exit, or any of its
2542  * aliases #kill or #terminate.
2543  *
2544  * thr.exit
2545  *
2546  * === Thread status
2547  *
2548  * Ruby provides a few instance methods for querying the state of a given
2549  * thread. To get a string with the current thread's state use #status
2550  *
2551  * thr = Thread.new { sleep }
2552  * thr.status # => "sleep"
2553  * thr.exit
2554  * thr.status # => false
2555  *
2556  * You can also use #alive? to tell if the thread is running or sleeping,
2557  * and #stop? if the thread is dead or sleeping.
2558  *
2559  * === Thread variables and scope
2560  *
2561  * Since threads are created with blocks, the same rules apply to other
2562  * Ruby blocks for variable scope. Any local variables created within this
2563  * block are accessible to only this thread.
2564  *
2565  * ==== Fiber-local vs. Thread-local
2566  *
2567  * Each fiber has its own bucket for Thread#[] storage. When you set a
2568  * new fiber-local it is only accessible within this Fiber. To illustrate:
2569  *
2570  * Thread.new {
2571  * Thread.current[:foo] = "bar"
2572  * Fiber.new {
2573  * p Thread.current[:foo] # => nil
2574  * }.resume
2575  * }.join
2576  *
2577  * This example uses #[] for getting and #[]= for setting fiber-locals,
2578  * you can also use #keys to list the fiber-locals for a given
2579  * thread and #key? to check if a fiber-local exists.
2580  *
2581  * When it comes to thread-locals, they are accessible within the entire
2582  * scope of the thread. Given the following example:
2583  *
2584  * Thread.new{
2585  * Thread.current.thread_variable_set(:foo, 1)
2586  * p Thread.current.thread_variable_get(:foo) # => 1
2587  * Fiber.new{
2588  * Thread.current.thread_variable_set(:foo, 2)
2589  * p Thread.current.thread_variable_get(:foo) # => 2
2590  * }.resume
2591  * p Thread.current.thread_variable_get(:foo) # => 2
2592  * }.join
2593  *
2594  * You can see that the thread-local +:foo+ carried over into the fiber
2595  * and was changed to +2+ by the end of the thread.
2596  *
2597  * This example makes use of #thread_variable_set to create new
2598  * thread-locals, and #thread_variable_get to reference them.
2599  *
2600  * There is also #thread_variables to list all thread-locals, and
2601  * #thread_variable? to check if a given thread-local exists.
2602  *
2603  * === Exception handling
2604  *
2605  * Any thread can raise an exception using the #raise instance method,
2606  * which operates similarly to Kernel#raise.
2607  *
2608  * However, it's important to note that an exception that occurs in any
2609  * thread except the main thread depends on #abort_on_exception. This
2610  * option is +false+ by default, meaning that any unhandled exception will
2611  * cause the thread to terminate silently when waited on by either #join
2612  * or #value. You can change this default by either #abort_on_exception=
2613  * +true+ or setting $DEBUG to +true+.
2614  *
2615  * With the addition of the class method ::handle_interrupt, you can now
2616  * handle exceptions asynchronously with threads.
2617  *
2618  * === Scheduling
2619  *
2620  * Ruby provides a few ways to support scheduling threads in your program.
2621  *
2622  * The first way is by using the class method ::stop, to put the current
2623  * running thread to sleep and schedule the execution of another thread.
2624  *
2625  * Once a thread is asleep, you can use the instance method #wakeup to
2626  * mark your thread as eligible for scheduling.
2627  *
2628  * You can also try ::pass, which attempts to pass execution to another
2629  * thread but is dependent on the OS whether a running thread will switch
2630  * or not. The same goes for #priority, which lets you hint to the thread
2631  * scheduler which threads you want to take precedence when passing
2632  * execution. This method is also dependent on the OS and may be ignored
2633  * on some platforms.
2634  *
2635  */
2636  rb_cThread = rb_define_class("Thread", rb_cObject);
2638 
2639 #if VM_COLLECT_USAGE_DETAILS
2640  /* ::RubyVM::USAGE_ANALYSIS_* */
2641 #define define_usage_analysis_hash(name) /* shut up rdoc -C */ \
2642  rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_"#name, rb_hash_new())
2643  define_usage_analysis_hash("INSN");
2644  define_usage_analysis_hash("REGS");
2645  define_usage_analysis_hash("INSN_BIGRAM");
2646 
2647  rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_INSN_STOP", usage_analysis_insn_stop, 0);
2648  rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_OPERAND_STOP", usage_analysis_operand_stop, 0);
2649  rb_define_singleton_method(rb_cRubyVM, "USAGE_ANALYSIS_REGISTER_STOP", usage_analysis_register_stop, 0);
2650 #endif
2651 
2652  /* ::RubyVM::OPTS, which shows vm build options */
2653  rb_define_const(rb_cRubyVM, "OPTS", opts = rb_ary_new());
2654 
2655 #if OPT_DIRECT_THREADED_CODE
2656  rb_ary_push(opts, rb_str_new2("direct threaded code"));
2657 #elif OPT_TOKEN_THREADED_CODE
2658  rb_ary_push(opts, rb_str_new2("token threaded code"));
2659 #elif OPT_CALL_THREADED_CODE
2660  rb_ary_push(opts, rb_str_new2("call threaded code"));
2661 #endif
2662 
2663 #if OPT_STACK_CACHING
2664  rb_ary_push(opts, rb_str_new2("stack caching"));
2665 #endif
2666 #if OPT_OPERANDS_UNIFICATION
2667  rb_ary_push(opts, rb_str_new2("operands unification]"));
2668 #endif
2669 #if OPT_INSTRUCTIONS_UNIFICATION
2670  rb_ary_push(opts, rb_str_new2("instructions unification"));
2671 #endif
2672 #if OPT_INLINE_METHOD_CACHE
2673  rb_ary_push(opts, rb_str_new2("inline method cache"));
2674 #endif
2675 #if OPT_BLOCKINLINING
2676  rb_ary_push(opts, rb_str_new2("block inlining"));
2677 #endif
2678 
2679  /* ::RubyVM::INSTRUCTION_NAMES */
2680  rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", rb_insns_name_array());
2681 
2682  /* ::RubyVM::DEFAULT_PARAMS
2683  * This constant variable shows VM's default parameters.
2684  * Note that changing these values does not affect VM execution.
2685  * Specification is not stable and you should not depend on this value.
2686  * Of course, this constant is MRI specific.
2687  */
2688  rb_define_const(rb_cRubyVM, "DEFAULT_PARAMS", vm_default_params());
2689 
2690  /* debug functions ::RubyVM::SDR(), ::RubyVM::NSDR() */
2691 #if VMDEBUG
2694 #else
2695  (void)sdr;
2696  (void)nsdr;
2697 #endif
2698 
2699  /* VM bootstrap: phase 2 */
2700  {
2701  rb_vm_t *vm = ruby_current_vm;
2702  rb_thread_t *th = GET_THREAD();
2703  VALUE filename = rb_str_new2("<main>");
2704  volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
2705  volatile VALUE th_self;
2706  rb_iseq_t *iseq;
2707 
2708  /* create vm object */
2709  vm->self = TypedData_Wrap_Struct(rb_cRubyVM, &vm_data_type, vm);
2710 
2711  /* create main thread */
2712  th_self = th->self = TypedData_Wrap_Struct(rb_cThread, &thread_data_type, th);
2713  rb_iv_set(th_self, "locals", rb_hash_new());
2714  vm->main_thread = th;
2715  vm->running_thread = th;
2716  th->vm = vm;
2717  th->top_wrapper = 0;
2718  th->top_self = rb_vm_top_self();
2720 
2722  st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id);
2723 
2724  rb_gc_register_mark_object(iseqval);
2725  GetISeqPtr(iseqval, iseq);
2726  th->cfp->iseq = iseq;
2727  th->cfp->pc = iseq->iseq_encoded;
2728  th->cfp->self = th->top_self;
2729  th->cfp->klass = Qnil;
2730 
2731  /*
2732  * The Binding of the top level scope
2733  */
2734  rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
2735  }
2737 
2738  /* vm_backtrace.c */
2741 }
2742 
2743 void
2745 {
2746  rb_thread_t *th = GET_VM()->main_thread;
2747  rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
2748  --cfp;
2749  RB_OBJ_WRITE(cfp->iseq->self, &cfp->iseq->location.path, filename);
2750 }
2751 
2752 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
2753 struct rb_objspace *rb_objspace_alloc(void);
2754 #endif
2755 
2756 void
2758 {
2759  /* VM bootstrap: phase 1 */
2760  rb_vm_t * vm = ruby_mimmalloc(sizeof(*vm));
2761  rb_thread_t * th = ruby_mimmalloc(sizeof(*th));
2762  if (!vm || !th) {
2763  fprintf(stderr, "[FATAL] failed to allocate memory\n");
2764  exit(EXIT_FAILURE);
2765  }
2766  MEMZERO(th, rb_thread_t, 1);
2768 
2769  vm_init2(vm);
2770 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
2771  vm->objspace = rb_objspace_alloc();
2772 #endif
2773  ruby_current_vm = vm;
2774 
2776  th->vm = vm;
2777  th_init(th, 0);
2780 }
2781 
2782 /* top self */
2783 
2784 static VALUE
2786 {
2787  return rb_str_new2("main");
2788 }
2789 
2790 VALUE
2792 {
2793  return GET_VM()->top_self;
2794 }
2795 
2796 void
2798 {
2799  rb_vm_t *vm = GET_VM();
2800 
2803  rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");
2804 
2805  /* initialize mark object array, hash */
2807 }
2808 
2809 VALUE *
2811 {
2812  return &vm->verbose;
2813 }
2814 
2815 VALUE *
2817 {
2818  return &vm->debug;
2819 }
2820 
2821 VALUE *
2823 {
2824  return ruby_vm_verbose_ptr(GET_VM());
2825 }
2826 
2827 VALUE *
2829 {
2830  return ruby_vm_debug_ptr(GET_VM());
2831 }
2832 
2833 /* iseq.c */
2835  VALUE insn, int op_no, VALUE op,
2836  int len, size_t pos, VALUE *pnop, VALUE child);
2837 
2838 #if VM_COLLECT_USAGE_DETAILS
2839 
2840 #define HASH_ASET(h, k, v) rb_hash_aset((h), (st_data_t)(k), (st_data_t)(v))
2841 
2842 /* uh = {
2843  * insn(Fixnum) => ihash(Hash)
2844  * }
2845  * ihash = {
2846  * -1(Fixnum) => count, # insn usage
2847  * 0(Fixnum) => ophash, # operand usage
2848  * }
2849  * ophash = {
2850  * val(interned string) => count(Fixnum)
2851  * }
2852  */
2853 static void
2854 vm_analysis_insn(int insn)
2855 {
2856  ID usage_hash;
2857  ID bigram_hash;
2858  static int prev_insn = -1;
2859 
2860  VALUE uh;
2861  VALUE ihash;
2862  VALUE cv;
2863 
2864  CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
2865  CONST_ID(bigram_hash, "USAGE_ANALYSIS_INSN_BIGRAM");
2866  uh = rb_const_get(rb_cRubyVM, usage_hash);
2867  if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) {
2868  ihash = rb_hash_new();
2869  HASH_ASET(uh, INT2FIX(insn), ihash);
2870  }
2871  if ((cv = rb_hash_aref(ihash, INT2FIX(-1))) == Qnil) {
2872  cv = INT2FIX(0);
2873  }
2874  HASH_ASET(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1));
2875 
2876  /* calc bigram */
2877  if (prev_insn != -1) {
2878  VALUE bi;
2879  VALUE ary[2];
2880  VALUE cv;
2881 
2882  ary[0] = INT2FIX(prev_insn);
2883  ary[1] = INT2FIX(insn);
2884  bi = rb_ary_new4(2, &ary[0]);
2885 
2886  uh = rb_const_get(rb_cRubyVM, bigram_hash);
2887  if ((cv = rb_hash_aref(uh, bi)) == Qnil) {
2888  cv = INT2FIX(0);
2889  }
2890  HASH_ASET(uh, bi, INT2FIX(FIX2INT(cv) + 1));
2891  }
2892  prev_insn = insn;
2893 }
2894 
2895 static void
2896 vm_analysis_operand(int insn, int n, VALUE op)
2897 {
2898  ID usage_hash;
2899 
2900  VALUE uh;
2901  VALUE ihash;
2902  VALUE ophash;
2903  VALUE valstr;
2904  VALUE cv;
2905 
2906  CONST_ID(usage_hash, "USAGE_ANALYSIS_INSN");
2907 
2908  uh = rb_const_get(rb_cRubyVM, usage_hash);
2909  if ((ihash = rb_hash_aref(uh, INT2FIX(insn))) == Qnil) {
2910  ihash = rb_hash_new();
2911  HASH_ASET(uh, INT2FIX(insn), ihash);
2912  }
2913  if ((ophash = rb_hash_aref(ihash, INT2FIX(n))) == Qnil) {
2914  ophash = rb_hash_new();
2915  HASH_ASET(ihash, INT2FIX(n), ophash);
2916  }
2917  /* intern */
2918  valstr = rb_insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
2919 
2920  /* set count */
2921  if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) {
2922  cv = INT2FIX(0);
2923  }
2924  HASH_ASET(ophash, valstr, INT2FIX(FIX2INT(cv) + 1));
2925 }
2926 
2927 static void
2928 vm_analysis_register(int reg, int isset)
2929 {
2930  ID usage_hash;
2931  VALUE uh;
2932  VALUE valstr;
2933  static const char regstrs[][5] = {
2934  "pc", /* 0 */
2935  "sp", /* 1 */
2936  "ep", /* 2 */
2937  "cfp", /* 3 */
2938  "self", /* 4 */
2939  "iseq", /* 5 */
2940  };
2941  static const char getsetstr[][4] = {
2942  "get",
2943  "set",
2944  };
2945  static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2];
2946 
2947  VALUE cv;
2948 
2949  CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS");
2950  if (syms[0] == 0) {
2951  char buff[0x10];
2952  int i;
2953 
2954  for (i = 0; i < (int)(sizeof(regstrs) / sizeof(regstrs[0])); i++) {
2955  int j;
2956  for (j = 0; j < 2; j++) {
2957  snprintf(buff, 0x10, "%d %s %-4s", i, getsetstr[j], regstrs[i]);
2958  syms[i][j] = ID2SYM(rb_intern(buff));
2959  }
2960  }
2961  }
2962  valstr = syms[reg][isset];
2963 
2964  uh = rb_const_get(rb_cRubyVM, usage_hash);
2965  if ((cv = rb_hash_aref(uh, valstr)) == Qnil) {
2966  cv = INT2FIX(0);
2967  }
2968  HASH_ASET(uh, valstr, INT2FIX(FIX2INT(cv) + 1));
2969 }
2970 
2971 #undef HASH_ASET
2972 
2973 void (*ruby_vm_collect_usage_func_insn)(int insn) = vm_analysis_insn;
2974 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = vm_analysis_operand;
2975 void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = vm_analysis_register;
2976 
2977 /* :nodoc: */
2978 static VALUE
2979 usage_analysis_insn_stop(VALUE self)
2980 {
2982  return Qnil;
2983 }
2984 
2985 /* :nodoc: */
2986 static VALUE
2987 usage_analysis_operand_stop(VALUE self)
2988 {
2990  return Qnil;
2991 }
2992 
2993 /* :nodoc: */
2994 static VALUE
2995 usage_analysis_register_stop(VALUE self)
2996 {
2998  return Qnil;
2999 }
3000 
3001 #else
3002 
3004 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = NULL;
3005 void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = NULL;
3006 
3007 #endif
3008 
3009 #if VM_COLLECT_USAGE_DETAILS
3010 /* @param insn instruction number */
3011 static void
3012 vm_collect_usage_insn(int insn)
3013 {
3014  if (RUBY_DTRACE_INSN_ENABLED()) {
3015  RUBY_DTRACE_INSN(rb_insns_name(insn));
3016  }
3018  (*ruby_vm_collect_usage_func_insn)(insn);
3019 }
3020 
3021 /* @param insn instruction number
3022  * @param n n-th operand
3023  * @param op operand value
3024  */
3025 static void
3026 vm_collect_usage_operand(int insn, int n, VALUE op)
3027 {
3028  if (RUBY_DTRACE_INSN_OPERAND_ENABLED()) {
3029  VALUE valstr;
3030 
3031  valstr = rb_insn_operand_intern(GET_THREAD()->cfp->iseq, insn, n, op, 0, 0, 0, 0);
3032 
3033  RUBY_DTRACE_INSN_OPERAND(RSTRING_PTR(valstr), rb_insns_name(insn));
3034  RB_GC_GUARD(valstr);
3035  }
3037  (*ruby_vm_collect_usage_func_operand)(insn, n, op);
3038 }
3039 
3040 /* @param reg register id. see code of vm_analysis_register() */
3041 /* @param iseset 0: read, 1: write */
3042 static void
3043 vm_collect_usage_register(int reg, int isset)
3044 {
3046  (*ruby_vm_collect_usage_func_register)(reg, isset);
3047 }
3048 #endif
3049 
3050