Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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 *
25 VM_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
35 VALUE *
36 rb_vm_ep_local_ep(VALUE *ep)
37 {
38 return VM_EP_LEP(ep);
39 }
40
41 static inline VALUE *
42 VM_CF_LEP(rb_control_frame_t *cfp)
43 {
44 return VM_EP_LEP(cfp->ep);
45 }
46
47 static inline VALUE *
48 VM_CF_PREV_EP(rb_control_frame_t * cfp)
49 {
50 return VM_EP_PREV_EP((cfp)->ep);
51 }
52
53 static inline rb_block_t *
54 VM_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
60 rb_block_t *
61 rb_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
67 static void vm_collect_usage_operand(int insn, int n, VALUE op);
68 static void vm_collect_usage_insn(int insn);
69 static void vm_collect_usage_register(int reg, int isset);
70 #endif
71
72 static VALUE
73 vm_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
89 VALUE rb_cRubyVM;
90 VALUE rb_cThread;
91 VALUE rb_cEnv;
92 VALUE rb_mRubyVMFrozenCore;
93
94 VALUE ruby_vm_const_missing_count = 0;
95 char ruby_vm_redefined_flag[BOP_LAST_];
96 rb_thread_t *ruby_current_thread = 0;
97 rb_vm_t *ruby_current_vm = 0;
98 rb_event_flag_t ruby_vm_event_flags;
99
100 static void thread_free(void *ptr);
101
102 void
103 rb_vm_change_state(void)
104 {
105 INC_VM_STATE_VERSION();
106 }
107
108 static void vm_clear_global_method_cache(void);
109
110 static void
111 vm_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
119 static void
120 vm_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
127 void
128 rb_vm_inc_const_missing_count(void)
129 {
130 ruby_vm_const_missing_count +=1;
131 }
132
133 /* control stack frame */
134
135 static void
136 vm_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
152 static void
153 vm_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
169 static void
170 vm_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
188 rb_control_frame_t *
189 rb_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
200 rb_control_frame_t *
201 rb_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
212 static rb_control_frame_t *
213 vm_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
236 void
237 ruby_vm_at_exit(void (*func)(rb_vm_t *))
238 {
239 rb_ary_push((VALUE)&GET_VM()->at_exit, (VALUE)func);
240 }
241
242 static void
243 ruby_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
268 static void
269 env_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
298 static void
299 env_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
310 static size_t
311 env_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
324 static const rb_data_type_t env_data_type = {
325 "VM/env",
326 {env_mark, env_free, env_memsize,},
327 };
328
329 static VALUE
330 env_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
341 static VALUE check_env_value(VALUE envval);
342
343 static int
344 check_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
359 static VALUE
360 check_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
372 static VALUE
373 vm_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
451 static int
452 collect_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
465 static int
466 collect_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
476 static int
477 vm_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
490 static void vm_rewrite_ep_in_errinfo(rb_thread_t *th);
491 static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block);
492 static VALUE vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp, VALUE *blockprocptr);
493
494 VALUE
495 rb_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
501 static VALUE
502 vm_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
526 static void
527 vm_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
552 void
553 rb_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
564 static VALUE
565 vm_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
573 VALUE
574 rb_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
611 static inline VALUE
612 invoke_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
655 static inline const rb_block_t *
656 check_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
667 static inline VALUE
668 vm_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
675 static inline VALUE
676 vm_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
683 static VALUE
684 vm_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
711 VALUE
712 rb_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
721 static rb_control_frame_t *
722 vm_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
733 static VALUE
734 vm_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
740 static void
741 vm_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
747 static VALUE
748 vm_svar_get(VALUE key)
749 {
750 rb_thread_t *th = GET_THREAD();
751 return vm_cfp_svar_get(th, th->cfp, key);
752 }
753
754 static void
755 vm_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
761 VALUE
762 rb_backref_get(void)
763 {
764 return vm_svar_get(1);
765 }
766
767 void
768 rb_backref_set(VALUE val)
769 {
770 vm_svar_set(1, val);
771 }
772
773 VALUE
774 rb_lastline_get(void)
775 {
776 return vm_svar_get(0);
777 }
778
779 void
780 rb_lastline_set(VALUE val)
781 {
782 vm_svar_set(0, val);
783 }
784
785 /* misc */
786
787 VALUE
788 rb_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
801 const char *
802 rb_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
815 int
816 rb_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
829 NODE *
830 rb_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
842 void
843 debug_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
853 VALUE
854 rb_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
867 static VALUE
868 make_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
899 void
900 rb_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
906 VALUE
907 rb_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
938 void
939 rb_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
946 NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val));
947
948 static void
949 vm_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
959 void
960 rb_iter_break(void)
961 {
962 vm_iter_break(GET_THREAD(), Qnil);
963 }
964
965 void
966 rb_iter_break_value(VALUE val)
967 {
968 vm_iter_break(GET_THREAD(), val);
969 }
970
971 /* optimization: redefine management */
972
973 static st_table *vm_opt_method_table = 0;
974
975 static int
976 vm_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
989 static void
990 rb_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
1002 static int
1003 check_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
1015 void
1016 rb_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
1023 static void
1024 add_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
1036 static void
1037 vm_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
1071 static const char *
1072 vm_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
1189 static VALUE
1190 vm_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
1428 VALUE
1429 rb_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
1441 VALUE
1442 rb_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
1454 int
1455 rb_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
1482 int
1483 rb_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
1488 int
1489 rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
1490 {
1491 return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp);
1492 }
1493
1494 VALUE
1495 rb_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
1518 VALUE
1519 rb_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
1538 static int
1539 vm_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
1546 void vm_trace_mark_event_hooks(rb_hook_list_t *hooks);
1547
1548 void
1549 rb_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
1595 int
1596 ruby_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
1628 static size_t
1629 vm_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
1645 static const rb_data_type_t vm_data_type = {
1646 "VM",
1647 {rb_vm_mark, vm_free, vm_memsize,},
1648 };
1649
1650
1651 static VALUE
1652 vm_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
1666 static size_t
1667 get_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
1683 static void
1684 check_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
1701 static void
1702 vm_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
1729 static void
1730 vm_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
1746 static VALUE *thread_recycle_stack_slot[RECYCLE_MAX];
1747 static int thread_recycle_stack_count = 0;
1748
1749 static VALUE *
1750 thread_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
1765 void
1766 rb_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
1778 static rb_thread_t *
1779 thread_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
1787 void
1788 rb_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
1856 static void
1857 thread_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
1897 static size_t
1898 thread_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
1918 const 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
1927 VALUE
1928 rb_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
1938 static VALUE
1939 thread_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
1952 static void
1953 th_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
1984 static VALUE
1985 ruby_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
2001 VALUE
2002 rb_thread_alloc(VALUE klass)
2003 {
2004 VALUE self = thread_alloc(klass);
2005 ruby_thread_init(self);
2006 return self;
2007 }
2008
2009 static void
2010 vm_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
2050 static VALUE
2051 m_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
2059 static VALUE
2060 m_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
2068 static VALUE
2069 m_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
2077 static VALUE
2078 m_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
2086 static VALUE
2087 m_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
2096 static VALUE
2097 m_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
2122 static VALUE
2123 m_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
2140 static VALUE
2141 m_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
2153 static VALUE
2154 m_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
2166 static int
2167 kwmerge_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
2174 static int
2175 kwmerge_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
2182 static VALUE
2183 m_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
2190 extern VALUE *rb_gc_stack_start;
2191 extern size_t rb_gc_stack_maxsize;
2192 #ifdef __ia64
2193 extern VALUE *rb_gc_register_stack_start;
2194 #endif
2195
2196 /* debug functions */
2197
2198 /* :nodoc: */
2199 static VALUE
2200 sdr(void)
2201 {
2202 rb_vm_bugreport();
2203 return Qnil;
2204 }
2205
2206 /* :nodoc: */
2207 static VALUE
2208 nsdr(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
2232 static VALUE usage_analysis_insn_stop(VALUE self);
2233 static VALUE usage_analysis_operand_stop(VALUE self);
2234 static VALUE usage_analysis_register_stop(VALUE self);
2235 #endif
2236
2237 void
2238 Init_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
2380 void
2381 rb_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
2390 struct rb_objspace *rb_objspace_alloc(void);
2391 #endif
2392
2393 void
2394 Init_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
2420 static VALUE
2421 main_to_s(VALUE obj)
2422 {
2423 return rb_str_new2("main");
2424 }
2425
2426 VALUE
2427 rb_vm_top_self(void)
2428 {
2429 return GET_VM()->top_self;
2430 }
2431
2432 void
2433 Init_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
2445 VALUE *
2446 ruby_vm_verbose_ptr(rb_vm_t *vm)
2447 {
2448 return &vm->verbose;
2449 }
2450
2451 VALUE *
2452 ruby_vm_debug_ptr(rb_vm_t *vm)
2453 {
2454 return &vm->debug;
2455 }
2456
2457 VALUE *
2458 rb_ruby_verbose_ptr(void)
2459 {
2460 return ruby_vm_verbose_ptr(GET_VM());
2461 }
2462
2463 VALUE *
2464 rb_ruby_debug_ptr(void)
2465 {
2466 return ruby_vm_debug_ptr(GET_VM());
2467 }
2468
2469 /* iseq.c */
2470 VALUE 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 */
2489 static void
2490 vm_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
2531 static void
2532 vm_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
2563 static void
2564 vm_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
2609 void (*ruby_vm_collect_usage_func_insn)(int insn) = vm_analysis_insn;
2610 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = vm_analysis_operand;
2611 void (*ruby_vm_collect_usage_func_register)(int reg, int isset) = vm_analysis_register;
2612
2613 /* :nodoc: */
2614 static VALUE
2615 usage_analysis_insn_stop(VALUE self)
2616 {
2617 ruby_vm_collect_usage_func_insn = 0;
2618 return Qnil;
2619 }
2620
2621 /* :nodoc: */
2622 static VALUE
2623 usage_analysis_operand_stop(VALUE self)
2624 {
2625 ruby_vm_collect_usage_func_operand = 0;
2626 return Qnil;
2627 }
2628
2629 /* :nodoc: */
2630 static VALUE
2631 usage_analysis_register_stop(VALUE self)
2632 {
2633 ruby_vm_collect_usage_func_register = 0;
2634 return Qnil;
2635 }
2636
2637 #else
2638
2639 void (*ruby_vm_collect_usage_func_insn)(int insn) = NULL;
2640 void (*ruby_vm_collect_usage_func_operand)(int insn, int n, VALUE op) = NULL;
2641 void (*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 */
2647 static void
2648 vm_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 */
2661 static void
2662 vm_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 */
2678 static void
2679 vm_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