From 7980e653e57ae5b539533dee1d0b1a00fc16ea5d Mon Sep 17 00:00:00 2001 From: ko1 Date: Sun, 24 Jun 2007 17:19:22 +0000 Subject: * call_cfunc.ci: removed. * insnhelper.ci: added. this function includes all functions that vm insns need. * common.mk: ditto. * insnhelper.h, vm.h, vm.c: move some declaration. * gc.h: remove GC_CHECK() macro because GC.stress is more useful. * compile.c, iseq.c, vm_dump: ditto. * gc.h, thread.c: move a prototype decalaration. * debug.c, debug.h: rename some functions. * compile.h: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12605 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 21 ++ call_cfunc.ci | 90 ------- common.mk | 8 +- compile.c | 17 -- compile.h | 39 ++- debug.c | 24 +- debug.h | 35 +-- gc.h | 1 + insnhelper.ci | 845 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ insnhelper.h | 4 +- iseq.c | 3 - thread.c | 3 - vm.c | 784 +---------------------------------------------------- vm.h | 16 +- vm_dump.c | 4 - 15 files changed, 932 insertions(+), 962 deletions(-) delete mode 100644 call_cfunc.ci create mode 100644 insnhelper.ci diff --git a/ChangeLog b/ChangeLog index 244760cd24..e5b9ec08c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Mon Jun 25 02:14:30 2007 Koichi Sasada + + * call_cfunc.ci: removed. + + * insnhelper.ci: added. this function includes all functions that + vm insns need. + + * common.mk: ditto. + + * insnhelper.h, vm.h, vm.c: move some declaration. + + * gc.h: remove GC_CHECK() macro because GC.stress is more useful. + + * compile.c, iseq.c, vm_dump: ditto. + + * gc.h, thread.c: move a prototype decalaration. + + * debug.c, debug.h: rename some functions. + + * compile.h: ditto. + Mon Jun 25 00:45:02 2007 Koichi Sasada * insns.def (invokesuper): fix error message. diff --git a/call_cfunc.ci b/call_cfunc.ci deleted file mode 100644 index d42bf1b14e..0000000000 --- a/call_cfunc.ci +++ /dev/null @@ -1,90 +0,0 @@ -/* -*-c-*- */ - -/* from ruby1.9/eval.c */ - -static inline VALUE -call_cfunc(VALUE (*func)(), VALUE recv, int len, int argc, const VALUE *argv) -{ - /* printf("len: %d, argc: %d\n", len, argc); */ - - if (len >= 0 && argc != len) { - rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", - argc, len); - } - - switch (len) { - case -2: - return (*func) (recv, rb_ary_new4(argc, argv)); - break; - case -1: - return (*func) (argc, argv, recv); - break; - case 0: - return (*func) (recv); - break; - case 1: - return (*func) (recv, argv[0]); - break; - case 2: - return (*func) (recv, argv[0], argv[1]); - break; - case 3: - return (*func) (recv, argv[0], argv[1], argv[2]); - break; - case 4: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3]); - break; - case 5: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]); - break; - case 6: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); - break; - case 7: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6]); - break; - case 8: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7]); - break; - case 9: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8]); - break; - case 10: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9]); - break; - case 11: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], - argv[10]); - break; - case 12: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], - argv[10], argv[11]); - break; - case 13: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12]); - break; - case 14: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12], argv[13]); - break; - case 15: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], - argv[11], argv[12], argv[13], argv[14]); - break; - default: - rb_raise(rb_eArgError, "too many arguments(%d)", len); - break; - } - return Qnil; /* not reached */ -} diff --git a/common.mk b/common.mk index e2df6060aa..47041139e1 100644 --- a/common.mk +++ b/common.mk @@ -560,10 +560,10 @@ iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}yarvcore.h {$(VPATH)}debug.h \ {$(VPATH)}intern.h {$(VPATH)}st.h {$(VPATH)}signal.h \ {$(VPATH)}gc.h {$(VPATH)}vm_opts.h {$(VPATH)}config.h {$(VPATH)}node.h \ {$(VPATH)}thread_$(THREAD_MODEL).h {$(VPATH)}insns_info.inc -vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}vm.h {$(VPATH)}insnhelper.h \ - {$(VPATH)}yarvcore.h {$(VPATH)}debug.h {$(VPATH)}ruby.h {$(VPATH)}config.h\ - {$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}signal.h {$(VPATH)}dln.h \ - {$(VPATH)}vm_evalbody.ci {$(VPATH)}call_cfunc.ci \ +vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}vm.h {$(VPATH)}yarvcore.h \ + {$(VPATH)}debug.h {$(VPATH)}ruby.h {$(VPATH)}config.h \ + {$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}signal.h {$(VPATH)}dln.h \ + {$(VPATH)}insnhelper.h {$(VPATH)}insnhelper.ci {$(VPATH)}vm_evalbody.ci \ {$(VPATH)}insns.inc {$(VPATH)}vm.inc {$(VPATH)}vmtc.inc \ {$(VPATH)}vm_opts.h {$(VPATH)}eval_intern.h \ {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \ diff --git a/compile.c b/compile.c index d376dc40b3..e84cc827ad 100644 --- a/compile.c +++ b/compile.c @@ -201,8 +201,6 @@ rb_iseq_compile(VALUE self, NODE *node) } } - GC_CHECK(); - if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) { ADD_INSN2(ret, 0, getdynamic, INT2FIX(1), INT2FIX(0)); ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ ); @@ -654,24 +652,20 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor) { /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */ - GC_CHECK(); if (CPDEBUG > 5) dump_disasm_list(FIRST_ELEMENT(anchor)); - GC_CHECK(); debugs("[compile step 3.1 (iseq_optimize)]\n"); iseq_optimize(iseq, anchor); if (CPDEBUG > 5) dump_disasm_list(FIRST_ELEMENT(anchor)); - GC_CHECK(); if (iseq->compile_data->option->instructions_unification) { debugs("[compile step 3.2 (iseq_insns_unification)]\n"); iseq_insns_unification(iseq, anchor); if (CPDEBUG > 5) dump_disasm_list(FIRST_ELEMENT(anchor)); - GC_CHECK(); } if (iseq->compile_data->option->stack_caching) { @@ -679,16 +673,13 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor) set_sequence_stackcaching(iseq, anchor); if (CPDEBUG > 5) dump_disasm_list(FIRST_ELEMENT(anchor)); - GC_CHECK(); } debugs("[compile step 4.1 (set_sequence)]\n"); set_sequence(iseq, anchor); if (CPDEBUG > 5) dump_disasm_list(FIRST_ELEMENT(anchor)); - GC_CHECK(); - GC_CHECK(); debugs("[compile step 4.2 (set_exception_table)]\n"); set_exception_table(iseq); @@ -697,7 +688,6 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor) debugs("[compile step 5 (iseq_translate_direct_threaded_code)] \n"); iseq_translate_direct_threaded_code(iseq); - GC_CHECK(); if (CPDEBUG > 1) { VALUE str = ruby_iseq_disasm(iseq->self); @@ -949,8 +939,6 @@ set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor) int k, pos, sp, stack_max = 0; - GC_CHECK(); - /* set label position */ list = FIRST_ELEMENT(anchor); k = pos = 0; @@ -989,8 +977,6 @@ set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor) generated_iseq = ALLOC_N(VALUE, pos); insn_info_tbl = ALLOC_N(struct insn_info_struct, k); - GC_CHECK(); - list = FIRST_ELEMENT(anchor); k = pos = sp = 0; @@ -2502,8 +2488,6 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) { int type; - GC_CHECK(); - if (node == 0) { if (!poped) { debug_nodeprint("NODE_NIL(implicit)"); @@ -2527,7 +2511,6 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) case NODE_METHOD:{ /* OK */ - bp(); COMPILE_ERROR(("BUG: unknown node: NODE_METHOD")); break; } diff --git a/compile.h b/compile.h index 9991232446..0e932c08a9 100644 --- a/compile.h +++ b/compile.h @@ -39,32 +39,31 @@ #if CPDEBUG > 0 -#define debugp(header, value) \ - (ruby_debug_indent(0, CPDEBUG, gl_node_level * 2), \ - ruby_debug_value(0, CPDEBUG, header, value)) +#define debugp(header, value) \ + (ruby_debug_print_indent(0, CPDEBUG, gl_node_level * 2), \ + ruby_debug_print_value(0, CPDEBUG, header, value)) -#define debugi(header, id) \ - (ruby_debug_indent(0, CPDEBUG, gl_node_level * 2), \ - ruby_debug_id(0, CPDEBUG, header, id)) +#define debugi(header, id) \ + (ruby_debug_print_indent(0, CPDEBUG, gl_node_level * 2), \ + ruby_debug_print_id(0, CPDEBUG, header, id)) -#define debugp_param(header, value) \ - (ruby_debug_indent(1, CPDEBUG, gl_node_level * 2), \ - ruby_debug_value(1, CPDEBUG, header, value)) +#define debugp_param(header, value) \ + (ruby_debug_print_indent(1, CPDEBUG, gl_node_level * 2), \ + ruby_debug_print_value(1, CPDEBUG, header, value)) -#define debugp_verbose(header, value) \ - (ruby_debug_indent(2, CPDEBUG, gl_node_level * 2), \ - ruby_debug_value(2, CPDEBUG, header, value)) +#define debugp_verbose(header, value) \ + (ruby_debug_print_indent(2, CPDEBUG, gl_node_level * 2), \ + ruby_debug_print_value(2, CPDEBUG, header, value)) -#define debugp_verbose_node(header, value) \ - (ruby_debug_indent(10, CPDEBUG, gl_node_level * 2), \ - ruby_debug_value(10, CPDEBUG, header, value)) +#define debugp_verbose_node(header, value) \ + (ruby_debug_print_indent(10, CPDEBUG, gl_node_level * 2), \ + ruby_debug_print_value(10, CPDEBUG, header, value)) -#define debug_nodeprint(node) \ - ruby_debug_indent(-1, CPDEBUG, gl_node_level*2); \ - printf("node: %s (%d)\n", ruby_node_name(nd_type(node)), nd_line(node)); \ - gl_node_level ++; +#define debug_node_start(node) \ + (ruby_debug_print_indent(-1, CPDEBUG, gl_node_level*2), \ + ruby_debug_print_node(10, CPDEBUG, header, node), gl_node_level++) \ -#define debug_nodeprint_close() gl_node_level --; +#define debug_node_end() gl_node_level --; #else diff --git a/debug.c b/debug.c index ec28be3eb8..1612e80eb5 100644 --- a/debug.c +++ b/debug.c @@ -14,7 +14,7 @@ #include "debug.h" void -ruby_debug_indent(int level, int debug_level, int indent_level) +ruby_debug_print_indent(int level, int debug_level, int indent_level) { if (level < debug_level) { int i; @@ -26,7 +26,7 @@ ruby_debug_indent(int level, int debug_level, int indent_level) } VALUE -ruby_debug_value(int level, int debug_level, char *header, VALUE obj) +ruby_debug_print_value(int level, int debug_level, char *header, VALUE obj) { if (level < debug_level) { VALUE str; @@ -39,13 +39,13 @@ ruby_debug_value(int level, int debug_level, char *header, VALUE obj) } void -ruby_debug_v(VALUE v) +ruby_debug_print_v(VALUE v) { - ruby_debug_value(0, 1, "", v); + ruby_debug_print_value(0, 1, "", v); } ID -ruby_debug_id(int level, int debug_level, char *header, ID id) +ruby_debug_print_id(int level, int debug_level, char *header, ID id) { if (level < debug_level) { fprintf(stderr, "DBG> %s: %s\n", header, rb_id2name(id)); @@ -55,7 +55,7 @@ ruby_debug_id(int level, int debug_level, char *header, ID id) } NODE * -ruby_debug_node(int level, int debug_level, char *header, NODE *node) +ruby_debug_print_node(int level, int debug_level, char *header, NODE *node) { if (level < debug_level) { fprintf(stderr, "DBG> %s: %s (%d)\n", header, @@ -64,18 +64,6 @@ ruby_debug_node(int level, int debug_level, char *header, NODE *node) return node; } - -void -ruby_debug_gc_check_func(void) -{ - int i; -#define GCMKMAX 0x10 - for (i = 0; i < GCMKMAX; i++) { - rb_ary_new2(1000); - } - rb_gc(); -} - void ruby_debug_breakpoint(void) { diff --git a/debug.h b/debug.h index 66ea10883f..6cf681d57d 100644 --- a/debug.h +++ b/debug.h @@ -16,35 +16,18 @@ #include "ruby/ruby.h" #include "ruby/node.h" -#define dpv(h,v) ruby_debug_value(-1, 0, h, v) -#define dp(v) ruby_debug_value(-1, 0, "", v) -#define dpi(i) ruby_debug_id(-1, 0, "", i) +#define dpv(h,v) ruby_debug_print_value(-1, 0, h, v) +#define dp(v) ruby_debug_print_value(-1, 0, "", v) +#define dpi(i) ruby_debug_print_id(-1, 0, "", i) +#define dpn(n) ruby_debug_print_node(-1, 0, "", n) + #define bp() ruby_debug_breakpoint() -#define dpn(n) ruby_debug_node(-1, 0, "", n) -VALUE ruby_debug_value(int level, int debug_level, char *header, VALUE v); -ID ruby_debug_id(int level, int debug_level, char *header, ID id); -NODE *ruby_debug_node(int level, int debug_level, char *header, NODE *node); -void ruby_debug_indent(int level, int debug_level, int indent_level); +VALUE ruby_debug_print_value(int level, int debug_level, char *header, VALUE v); +ID ruby_debug_print_id(int level, int debug_level, char *header, ID id); +NODE *ruby_debug_print_node(int level, int debug_level, char *header, NODE *node); +void ruby_debug_print_indent(int level, int debug_level, int indent_level); void ruby_debug_breakpoint(void); void ruby_debug_gc_check_func(void); -#if GCDEBUG == 1 - -#define GC_CHECK() \ - gc_check_func() - -#elif GCDEBUG == 2 - -#define GC_CHECK() \ - (printf("** %s:%d gc start\n", __FILE__, __LINE__), \ - ruby_debug_gc_check_func(), \ - printf("** end\n")) - -#else - -#define GC_CHECK() - -#endif - #endif /* _DEBUG_H_INCLUDED_ */ diff --git a/gc.h b/gc.h index b9b1eb4ece..0c3d351416 100644 --- a/gc.h +++ b/gc.h @@ -3,6 +3,7 @@ #define RUBY_GC_H 1 NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); +NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); /* for GC debug */ diff --git a/insnhelper.ci b/insnhelper.ci new file mode 100644 index 0000000000..05cb6a03e8 --- /dev/null +++ b/insnhelper.ci @@ -0,0 +1,845 @@ +/* -*-c-*- */ +/********************************************************************** + + insnhelper.ci - instruction helper functions. + + $Author$ + $Date$ + + Copyright (C) 2007 Koichi Sasada + +**********************************************************************/ + +/* finish iseq array */ + +#include "insns.inc" + +#if OPT_STACK_CACHING +static VALUE yarv_finish_insn_seq[1] = { BIN(finish_SC_ax_ax) }; +#elif OPT_CALL_THREADED_CODE +static VALUE const yarv_finish_insn_seq[1] = { 0 }; +#else +static VALUE yarv_finish_insn_seq[1] = { BIN(finish) }; +#endif + +/* control stack frame */ + +static inline rb_control_frame_t * +vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE magic, + VALUE self, VALUE specval, VALUE *pc, + VALUE *sp, VALUE *lfp, int local_size) +{ + VALUE *dfp; + rb_control_frame_t *cfp; + int i; + + /* nil initialize */ + for (i=0; i < local_size; i++) { + *sp = Qnil; + sp++; + } + + /* set special val */ + *sp = GC_GUARDED_PTR(specval); + dfp = sp; + + if (lfp == 0) { + lfp = sp; + } + + cfp = th->cfp = th->cfp - 1; + cfp->pc = pc; + cfp->sp = sp + 1; + cfp->bp = sp + 1; + cfp->iseq = iseq; + cfp->magic = magic; + cfp->self = self; + cfp->lfp = lfp; + cfp->dfp = dfp; + cfp->proc = 0; + +#define COLLECT_PROFILE 0 +#if COLLECT_PROFILE + cfp->prof_time_self = clock(); + cfp->prof_time_chld = 0; +#endif + + return cfp; +} + +static inline void +vm_pop_frame(rb_thread_t *th) +{ +#if COLLECT_PROFILE + rb_control_frame_t *cfp = th->cfp; + + if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { + VALUE current_time = clock(); + rb_control_frame_t *cfp = th->cfp; + cfp->prof_time_self = current_time - cfp->prof_time_self; + (cfp+1)->prof_time_chld += cfp->prof_time_self; + + cfp->iseq->profile.count++; + cfp->iseq->profile.time_cumu = cfp->prof_time_self; + cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld; + } + else if (0 /* c method? */) { + + } +#endif + th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); +} + +/* method dispatch */ + +static inline int +vm_callee_setup_arg(rb_thread_t *th, rb_iseq_t *iseq, + int argc, VALUE *argv, rb_block_t **block) +{ + const int m = iseq->argc; + const int orig_argc = argc; + + if (iseq->arg_simple) { + /* simple check */ + if (argc != m) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", + argc, m); + } + return 0; + } + else { + VALUE * const dst = argv; + int opt_pc = 0; + + /* mandatory */ + if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", + argc, m + iseq->arg_post_len); + } + + argv += m; + argc -= m; + + /* post arguments */ + if (iseq->arg_post_len) { + int i; + + if (!(orig_argc < iseq->arg_post_start)) { + VALUE *new_argv = ALLOCA_N(VALUE, argc); + MEMCPY(new_argv, argv, VALUE, argc); + argv = new_argv; + } + + for (i=0; iarg_post_len; i++) { + dst[iseq->arg_post_start + iseq->arg_post_len - (i + 1)] = argv[argc - 1]; + argc = argc - 1; + } + } + + /* opt arguments */ + if (iseq->arg_opts) { + const int opts = iseq->arg_opts - 1 /* no opt */; + + if (iseq->arg_rest == -1 && argc > opts) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", orig_argc, m + opts); + } + + if (argc > opts) { + argc -= opts; + argv += opts; + opt_pc = iseq->arg_opt_tbl[opts]; /* no opt */ + } + else { + opt_pc = iseq->arg_opt_tbl[argc]; + argc = 0; + } + } + + /* rest arguments */ + if (iseq->arg_rest != -1) { + dst[iseq->arg_rest] = rb_ary_new4(argc, argv); + } + + /* block arguments */ + if (iseq->arg_block != -1) { + VALUE blockval = Qnil; + rb_block_t * const blockptr = *block; + + if (blockptr) { + /* make Proc object */ + if (blockptr->proc == 0) { + rb_proc_t *proc; + + th->mark_stack_len = orig_argc; /* for GC */ + blockval = vm_make_proc(th, th->cfp, blockptr); + th->mark_stack_len = 0; + + GetProcPtr(blockval, proc); + *block = &proc->block; + } + else { + blockval = blockptr->proc; + } + } + + dst[iseq->arg_block] = blockval; /* Proc or nil */ + } + + return opt_pc; + } +} + +static inline int +caller_setup_args(rb_thread_t *th, rb_control_frame_t *cfp, + VALUE flag, int argc, rb_iseq_t *blockiseq, rb_block_t **block) +{ + rb_block_t *blockptr = 0; + + if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { + rb_proc_t *po; + VALUE proc; + + proc = *(--cfp->sp); + + if (proc != Qnil) { + if (!rb_obj_is_proc(proc)) { + proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); + if (!rb_obj_is_proc(proc)) { + rb_raise(rb_eTypeError, + "wrong argument type %s (expected Proc)", + rb_obj_classname(proc)); + } + } + GetProcPtr(proc, po); + blockptr = &po->block; + RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; + *block = blockptr; + } + } + else if (blockiseq) { + blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); + blockptr->iseq = blockiseq; + blockptr->proc = 0; + *block = blockptr; + } + + /* expand top of stack? */ + if (flag & VM_CALL_ARGS_SPLAT_BIT) { + VALUE ary = *(cfp->sp - 1); + VALUE *ptr; + int i; + VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat"); + + if (NIL_P(tmp)) { + /* do nothing */ + } + else { + int len = RARRAY_LEN(tmp); + ptr = RARRAY_PTR(tmp); + cfp->sp -= 1; + + CHECK_STACK_OVERFLOW(cfp, len); + + for (i = 0; i < len; i++) { + *cfp->sp++ = ptr[i]; + } + argc += i-1; + } + } + + return argc; +} + +static inline VALUE +call_cfunc(VALUE (*func)(), VALUE recv, int len, int argc, const VALUE *argv) +{ + /* printf("len: %d, argc: %d\n", len, argc); */ + + if (len >= 0 && argc != len) { + rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", + argc, len); + } + + switch (len) { + case -2: + return (*func) (recv, rb_ary_new4(argc, argv)); + break; + case -1: + return (*func) (argc, argv, recv); + break; + case 0: + return (*func) (recv); + break; + case 1: + return (*func) (recv, argv[0]); + break; + case 2: + return (*func) (recv, argv[0], argv[1]); + break; + case 3: + return (*func) (recv, argv[0], argv[1], argv[2]); + break; + case 4: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3]); + break; + case 5: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]); + break; + case 6: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); + break; + case 7: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6]); + break; + case 8: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7]); + break; + case 9: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8]); + break; + case 10: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9]); + break; + case 11: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], + argv[10]); + break; + case 12: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], + argv[10], argv[11]); + break; + case 13: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12]); + break; + case 14: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12], argv[13]); + break; + case 15: + return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12], argv[13], argv[14]); + break; + default: + rb_raise(rb_eArgError, "too many arguments(%d)", len); + break; + } + return Qnil; /* not reached */ +} + +static inline VALUE +vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, int num, + ID id, VALUE recv, VALUE klass, NODE *mn, rb_block_t *blockptr) +{ + VALUE val; + + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); + { + rb_control_frame_t *cfp = + vm_push_frame(th, 0, FRAME_MAGIC_CFUNC, + recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1); + + cfp->method_id = id; + cfp->method_klass = klass; + + reg_cfp->sp -= num + 1; + + val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1); + + if (reg_cfp != th->cfp + 1) { + rb_bug("cfp consistency error - send"); + } + vm_pop_frame(th); + } + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); + + return val; +} + +static inline VALUE +vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv, + VALUE klass, int argc, VALUE *argv) +{ + rb_control_frame_t *cfp = th->cfp; + rb_proc_t *proc; + VALUE val; + + /* control block frame */ + (cfp-2)->method_id = id; + (cfp-2)->method_klass = klass; + + GetProcPtr(procval, proc); + val = vm_invoke_proc(th, proc, recv, argc, argv); + return val; +} + +static inline VALUE +vm_method_missing(rb_thread_t *th, ID id, VALUE recv, int num, + rb_block_t *blockptr, int opt) +{ + rb_control_frame_t *reg_cfp = th->cfp; + VALUE *argv = STACK_ADDR_FROM_TOP(num + 1); + VALUE val; + argv[0] = ID2SYM(id); + th->method_missing_reason = opt; + th->passed_block = blockptr; + val = rb_funcall2(recv, idMethodMissing, num + 1, argv); + POPN(num + 1); + return val; +} + +static inline void +vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, + int argc, rb_block_t *blockptr, VALUE flag, + VALUE iseqval, VALUE recv, VALUE klass) +{ + rb_iseq_t *iseq; + int opt_pc, i; + VALUE *rsp = cfp->sp - argc; + VALUE *sp; + + /* TODO: eliminate it */ + GetISeqPtr(iseqval, iseq); + + opt_pc = vm_callee_setup_arg(th, iseq, argc, rsp, &blockptr); + sp = rsp + iseq->arg_size; + + /* stack overflow check */ + CHECK_STACK_OVERFLOW(cfp, iseq->stack_max + 0x10); + + if (flag & VM_CALL_TAILCALL_BIT) { + VALUE *p_rsp; + cfp = ++th->cfp; /* pop cf */ + p_rsp = th->cfp->sp; + + /* copy arguments */ + for (i=0; i < (sp - rsp); i++) { + p_rsp[i] = rsp[i]; + } + + sp -= rsp - p_rsp; + + /* clear local variables */ + for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { + *sp++ = Qnil; + } + + vm_push_frame(th, iseq, + FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, + iseq->iseq_encoded + opt_pc, sp, 0, 0); + } + else { + if (0) printf("local_size: %d, arg_size: %d\n", + iseq->local_size, iseq->arg_size); + + /* clear local variables */ + for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { + *sp++ = Qnil; + } + + vm_push_frame(th, iseq, + FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, + iseq->iseq_encoded + opt_pc, sp, 0, 0); + + cfp->sp = rsp - 1 /* recv */; + } +} + +static inline VALUE +vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, + int num, rb_block_t *blockptr, VALUE flag, + ID id, NODE *mn, VALUE recv, VALUE klass) +{ + VALUE val; + + start_method_dispatch: + + /* method missing */ + if (mn == 0) { + if (id == idMethodMissing) { + rb_bug("method missing"); + } + else { + int stat = 0; + if (flag & VM_CALL_VCALL_BIT) { + stat |= NOEX_VCALL; + } + if (flag & VM_CALL_SUPER_BIT) { + stat |= NOEX_SUPER; + } + val = vm_method_missing(th, id, recv, num, blockptr, stat); + } + } + else if (!(flag & VM_CALL_FCALL_BIT) && + (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) { + int stat = NOEX_PRIVATE; + if (flag & VM_CALL_VCALL_BIT) { + stat |= NOEX_VCALL; + } + val = vm_method_missing(th, id, recv, num, blockptr, stat); + } + else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) { + VALUE defined_class = mn->nd_clss; + + if (TYPE(defined_class) == T_ICLASS) { + defined_class = RBASIC(defined_class)->klass; + } + + if (!rb_obj_is_kind_of(cfp->self, rb_class_real(defined_class))) { + val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); + } + else { + goto normal_method_dispatch; + } + } + + /* dispatch method */ + else { + NODE *node; + normal_method_dispatch: + + node = mn->nd_body; + switch (nd_type(node)) { + case RUBY_VM_METHOD_NODE:{ + vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv, klass); + return Qundef; + } + case NODE_CFUNC:{ + val = vm_call_cfunc(th, cfp, num, id, recv, klass, node, blockptr); + break; + } + case NODE_ATTRSET:{ + val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1)); + cfp->sp -= 2; + break; + } + case NODE_IVAR:{ + val = rb_ivar_get(recv, node->nd_vid); + cfp->sp -= 1; + break; + } + case NODE_BMETHOD:{ + VALUE *argv = cfp->sp - num; + val = vm_call_bmethod(th, id, node->nd_cval, recv, klass, num, argv); + cfp->sp += - num - 1; + break; + } + case NODE_ZSUPER:{ + klass = RCLASS(mn->nd_clss)->super; + mn = rb_method_node(klass, id); + + if (mn != 0) { + goto normal_method_dispatch; + } + else { + goto start_method_dispatch; + } + } + default:{ + printf("node: %s\n", ruby_node_name(nd_type(node))); + rb_bug("eval_invoke_method: unreachable"); + /* unreachable */ + break; + } + } + } + + RUBY_VM_CHECK_INTS(); + return val; +} + +/* cref */ + +static NODE * +lfp_get_special_cref(VALUE *lfp) +{ + struct RValues *values; + if (((VALUE)(values = (void *)lfp[-1])) != Qnil && values->basic.klass) { + return (NODE *)values->basic.klass; + } + else { + return 0; + } +} + +static void +check_svar(void) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp = th->cfp; + while ((void *)(cfp + 1) < (void *)(th->stack + th->stack_size)) { + /* printf("cfp: %p\n", cfp->magic); */ + if (cfp->lfp && cfp->lfp[-1] != Qnil && + TYPE(cfp->lfp[-1]) != T_VALUES) { + /* dp(cfp->lfp[-1]); */ + rb_bug("!!!illegal svar!!!"); + } + cfp++; + } +} + +static struct RValues * +new_value(void) +{ + struct RValues *val = RVALUES(rb_newobj()); + OBJSETUP(val, 0, T_VALUES); + val->v1 = val->v2 = val->v3 = Qnil; + return val; +} + +static VALUE * +lfp_svar(VALUE *lfp, int cnt) +{ + struct RValues *val; + rb_thread_t *th = GET_THREAD(); + + if (th->local_lfp != lfp) { + val = (struct RValues *)lfp[-1]; + if ((VALUE)val == Qnil) { + val = new_value(); + lfp[-1] = (VALUE)val; + } + } + else { + val = (struct RValues *)th->local_svar; + if ((VALUE)val == Qnil) { + val = new_value(); + th->local_svar = (VALUE)val; + } + } + switch (cnt) { + case -1: + return &val->basic.klass; + case 0: + return &val->v1; + case 1: + return &val->v2; + default:{ + VALUE ary; + if ((ary = val->v3) == Qnil) { + ary = val->v3 = rb_ary_new(); + } + if (RARRAY_LEN(ary) <= cnt) { + rb_ary_store(ary, cnt, Qnil); + } + return &RARRAY_PTR(ary)[cnt]; + } + } +} + +static NODE * +lfp_set_special_cref(VALUE *lfp, NODE * cref) +{ + struct RValues *values = (void *) lfp[-1]; + VALUE *pv; + NODE *old_cref; + + if (VMDEBUG) { + check_svar(); + } + + if (cref == 0 && ((VALUE)values == Qnil || values->basic.klass == 0)) { + old_cref = 0; + } + else { + pv = lfp_svar(lfp, -1); + old_cref = (NODE *) * pv; + *pv = (VALUE)cref; + } + return old_cref; +} + +static NODE * +get_cref(rb_iseq_t *iseq, VALUE *lfp) +{ + NODE *cref; + if ((cref = lfp_get_special_cref(lfp)) != 0) { + /* */ + } + else if ((cref = iseq->cref_stack) != 0) { + /* */ + } + else { + rb_bug("get_cref: unreachable"); + } + return cref; +} + +static inline VALUE +vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq, + VALUE klass, ID id, int is_defined) +{ + VALUE val; + + if (klass == Qnil) { + /* in current lexical scope */ + NODE *root_cref = get_cref(iseq, th->cfp->lfp); + NODE *cref = root_cref; + + while (cref && cref->nd_next) { + klass = cref->nd_clss; + cref = cref->nd_next; + + if (klass == 0) { + continue; + } + if (NIL_P(klass)) { + if (is_defined) { + /* TODO: check */ + return 1; + } + else { + klass = CLASS_OF(th->cfp->self); + return rb_const_get(klass, id); + } + } + search_continue: + if (RCLASS(klass)->iv_tbl && + st_lookup(RCLASS(klass)->iv_tbl, id, &val)) { + if (val == Qundef) { + rb_autoload_load(klass, id); + goto search_continue; + } + else { + if (is_defined) { + return 1; + } + else { + return val; + } + } + } + } + klass = root_cref->nd_clss; + if (is_defined) { + return rb_const_defined(klass, id); + } + else { + return rb_const_get(klass, id); + } + } + else { + switch (TYPE(klass)) { + case T_CLASS: + case T_MODULE: + break; + default: + rb_raise(rb_eTypeError, "%s is not a class/module", + RSTRING_PTR(rb_obj_as_string(klass))); + } + if (is_defined) { + return rb_const_defined(klass, id); + } + else { + return rb_const_get(klass, id); + } + } +} + +static inline VALUE +vm_get_cvar_base(rb_thread_t *th, rb_iseq_t *iseq) +{ + NODE *cref = get_cref(iseq, th->cfp->lfp); + VALUE klass = Qnil; + + if (cref) { + klass = cref->nd_clss; + if (!cref->nd_next) { + rb_warn("class variable access from toplevel"); + } + } + if (NIL_P(klass)) { + rb_raise(rb_eTypeError, "no class variables available"); + } + return klass; +} + +static inline void +vm_define_method(rb_thread_t *th, VALUE obj, + ID id, rb_iseq_t *miseq, rb_num_t is_singleton, NODE *cref) +{ + NODE *newbody; + int noex = cref->nd_visi; + VALUE klass = cref->nd_clss; + + if (is_singleton) { + if (FIXNUM_P(obj) || SYMBOL_P(obj)) { + rb_raise(rb_eTypeError, + "can't define singleton method \"%s\" for %s", + rb_id2name(id), rb_obj_classname(obj)); + } + + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + + klass = rb_singleton_class(obj); + noex = NOEX_PUBLIC; + } + + /* dup */ + COPY_CREF(miseq->cref_stack, cref); + miseq->klass = klass; + miseq->defined_method_id = id; + newbody = NEW_NODE(RUBY_VM_METHOD_NODE, 0, miseq->self, 0); + rb_add_method(klass, id, newbody, noex); + + if (!is_singleton && noex == NOEX_MODFUNC) { + rb_add_method(rb_singleton_class(klass), id, newbody, NOEX_PUBLIC); + } + INC_VM_STATE_VERSION(); +} + +static inline NODE * +vm_method_search(VALUE id, VALUE klass, IC ic) +{ + NODE *mn; + +#if OPT_INLINE_METHOD_CACHE + { + if (LIKELY(klass == ic->ic_klass) && + LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) { + mn = ic->ic_method; + } + else { + mn = rb_method_node(klass, id); + ic->ic_klass = klass; + ic->ic_method = mn; + ic->ic_vmstat = GET_VM_STATE_VERSION(); + } + } +#else + mn = rb_method_node(klass, id); +#endif + return mn; +} + +static inline int +block_proc_is_lambda(VALUE procval) +{ + rb_proc_t *proc; + + if (procval) { + GetProcPtr(procval, proc); + return proc->is_lambda; + } + else { + return 0; + } +} + +static void +call_yarv_end_proc(VALUE data) +{ + rb_proc_call(data, rb_ary_new2(0)); +} diff --git a/insnhelper.h b/insnhelper.h index 1fe19128b7..29c25d6122 100644 --- a/insnhelper.h +++ b/insnhelper.h @@ -13,8 +13,10 @@ #ifndef _INSNHELPER_H_INCLUDED_ #define _INSNHELPER_H_INCLUDED_ +#include "ruby/ruby.h" #include "vm.h" + /* * deal with control frame pointer */ @@ -143,7 +145,7 @@ while (0) /* optimize insn */ #define FIXNUM_2_P(a, b) ((a) & (b) & 1) -#define BASIC_OP_UNREDEFINED_P(op) ((yarv_redefined_flag & (op)) == 0) +#define BASIC_OP_UNREDEFINED_P(op) ((ruby_vm_redefined_flag & (op)) == 0) #define HEAP_CLASS_OF(obj) RBASIC(obj)->klass #define CALL_METHOD(num, blockptr, flag, id, mn, recv, klass) do { \ diff --git a/iseq.c b/iseq.c index e7482e9ba1..b1f7ba2204 100644 --- a/iseq.c +++ b/iseq.c @@ -664,7 +664,6 @@ ruby_iseq_disasm_insn(VALUE ret, VALUE *iseq, int pos, child); rb_str_concat(str, opstr); - GC_CHECK(); if (types[j + 1]) { rb_str_cat2(str, ", "); } @@ -801,8 +800,6 @@ ruby_iseq_disasm(VALUE self) rb_str_cat2(str, "\n"); } - GC_CHECK(); - /* show each line */ for (i = 0; i < size;) { i += ruby_iseq_disasm_insn(str, iseq, i, iseqdat, child); diff --git a/thread.c b/thread.c index 2ac91ab8b7..7aec816dc5 100644 --- a/thread.c +++ b/thread.c @@ -82,9 +82,6 @@ st_delete_wrap(st_table * table, VALUE key) static rb_unblock_function_t* set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func); -NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); -NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); - #define GVL_UNLOCK_BEGIN() do { \ rb_thread_t *_th_stored = GET_THREAD(); \ rb_gc_save_machine_context(_th_stored); \ diff --git a/vm.c b/vm.c index cace275d85..d1b9cb79a1 100644 --- a/vm.c +++ b/vm.c @@ -13,27 +13,16 @@ #include "ruby/node.h" #include "ruby/st.h" #include "gc.h" - -#include "yarvcore.h" -#include "vm.h" -#include "insnhelper.h" -#include "insns.inc" #include "eval_intern.h" -VALUE rb_cEnv; - -#define PROCDEBUG 0 -#define VM_DEBUG 0 +#include "insnhelper.h" +#include "insnhelper.ci" #define BUFSIZE 0x100 +#define PROCDEBUG 0 -#define EVALBODY_HELPER_FUNCTION static inline - -typedef unsigned long rb_num_t; -typedef unsigned long lindex_t; -typedef unsigned long dindex_t; - -typedef rb_num_t GENTRY; +VALUE rb_cEnv; +VALUE ruby_vm_global_state_version = 1; void vm_analysis_operand(int insn, int n, VALUE op); void vm_analysis_register(int reg, int isset); @@ -49,93 +38,13 @@ static NODE *lfp_set_special_cref(VALUE *lfp, NODE * cref); static inline int block_proc_is_lambda(VALUE procval); -#if OPT_STACK_CACHING -static VALUE yarv_finish_insn_seq[1] = { BIN(finish_SC_ax_ax) }; -#elif OPT_CALL_THREADED_CODE -static VALUE const yarv_finish_insn_seq[1] = { 0 }; -#else -static VALUE yarv_finish_insn_seq[1] = { BIN(finish) }; -#endif - -#include "call_cfunc.ci" - -static VALUE vm_global_state_version = 1; - void rb_vm_change_state(void) { INC_VM_STATE_VERSION(); } -/* - * prepare stack frame - */ -static inline rb_control_frame_t * -vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE magic, - VALUE self, VALUE specval, VALUE *pc, - VALUE *sp, VALUE *lfp, int local_size) -{ - VALUE *dfp; - rb_control_frame_t *cfp; - int i; - - /* nil initialize */ - for (i=0; i < local_size; i++) { - *sp = Qnil; - sp++; - } - - /* set special val */ - *sp = GC_GUARDED_PTR(specval); - dfp = sp; - - if (lfp == 0) { - lfp = sp; - } - - cfp = th->cfp = th->cfp - 1; - cfp->pc = pc; - cfp->sp = sp + 1; - cfp->bp = sp + 1; - cfp->iseq = iseq; - cfp->magic = magic; - cfp->self = self; - cfp->lfp = lfp; - cfp->dfp = dfp; - cfp->proc = 0; - -#define COLLECT_PROFILE 0 -#if COLLECT_PROFILE - cfp->prof_time_self = clock(); - cfp->prof_time_chld = 0; -#endif - - return cfp; -} - -static inline void -vm_pop_frame(rb_thread_t *th) -{ -#if COLLECT_PROFILE - rb_control_frame_t *cfp = th->cfp; - - if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { - VALUE current_time = clock(); - rb_control_frame_t *cfp = th->cfp; - cfp->prof_time_self = current_time - cfp->prof_time_self; - (cfp+1)->prof_time_chld += cfp->prof_time_self; - - cfp->iseq->profile.count++; - cfp->iseq->profile.time_cumu = cfp->prof_time_self; - cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld; - } - else if (0 /* c method? */) { - - } -#endif - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); -} - +/* control stack frame */ VALUE vm_set_finish_env(rb_thread_t *th) { @@ -179,386 +88,6 @@ vm_set_eval_stack(rb_thread_t *th, VALUE iseqval) return 0; } -/* return opt_pc */ -static inline int -vm_callee_setup_arg(rb_thread_t *th, rb_iseq_t *iseq, - int argc, VALUE *argv, rb_block_t **block) -{ - const int m = iseq->argc; - const int orig_argc = argc; - - if (iseq->arg_simple) { - /* simple check */ - if (argc != m) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", - argc, m); - } - return 0; - } - else { - VALUE * const dst = argv; - int opt_pc = 0; - - /* mandatory */ - if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", - argc, m + iseq->arg_post_len); - } - - argv += m; - argc -= m; - - /* post arguments */ - if (iseq->arg_post_len) { - int i; - - if (!(orig_argc < iseq->arg_post_start)) { - VALUE *new_argv = ALLOCA_N(VALUE, argc); - MEMCPY(new_argv, argv, VALUE, argc); - argv = new_argv; - } - - for (i=0; iarg_post_len; i++) { - dst[iseq->arg_post_start + iseq->arg_post_len - (i + 1)] = argv[argc - 1]; - argc = argc - 1; - } - } - - /* opt arguments */ - if (iseq->arg_opts) { - const int opts = iseq->arg_opts - 1 /* no opt */; - - if (iseq->arg_rest == -1 && argc > opts) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", orig_argc, m + opts); - } - - if (argc > opts) { - argc -= opts; - argv += opts; - opt_pc = iseq->arg_opt_tbl[opts]; /* no opt */ - } - else { - opt_pc = iseq->arg_opt_tbl[argc]; - argc = 0; - } - } - - /* rest arguments */ - if (iseq->arg_rest != -1) { - dst[iseq->arg_rest] = rb_ary_new4(argc, argv); - } - - /* block arguments */ - if (iseq->arg_block != -1) { - VALUE blockval = Qnil; - rb_block_t * const blockptr = *block; - - if (blockptr) { - /* make Proc object */ - if (blockptr->proc == 0) { - rb_proc_t *proc; - - th->mark_stack_len = orig_argc; /* for GC */ - blockval = vm_make_proc(th, th->cfp, blockptr); - th->mark_stack_len = 0; - - GetProcPtr(blockval, proc); - *block = &proc->block; - } - else { - blockval = blockptr->proc; - } - } - - dst[iseq->arg_block] = blockval; /* Proc or nil */ - } - - return opt_pc; - } -} - -static inline int -caller_setup_args(rb_thread_t *th, rb_control_frame_t *cfp, - VALUE flag, int argc, rb_iseq_t *blockiseq, rb_block_t **block) -{ - rb_block_t *blockptr = 0; - - if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { - rb_proc_t *po; - VALUE proc; - - proc = *(--cfp->sp); - - if (proc != Qnil) { - if (!rb_obj_is_proc(proc)) { - proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); - if (!rb_obj_is_proc(proc)) { - rb_raise(rb_eTypeError, - "wrong argument type %s (expected Proc)", - rb_obj_classname(proc)); - } - } - GetProcPtr(proc, po); - blockptr = &po->block; - RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; - *block = blockptr; - } - } - else if (blockiseq) { - blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); - blockptr->iseq = blockiseq; - blockptr->proc = 0; - *block = blockptr; - } - - /* expand top of stack? */ - if (flag & VM_CALL_ARGS_SPLAT_BIT) { - VALUE ary = *(cfp->sp - 1); - VALUE *ptr; - int i; - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat"); - - if (NIL_P(tmp)) { - /* do nothing */ - } - else { - int len = RARRAY_LEN(tmp); - ptr = RARRAY_PTR(tmp); - cfp->sp -= 1; - - CHECK_STACK_OVERFLOW(cfp, len); - - for (i = 0; i < len; i++) { - *cfp->sp++ = ptr[i]; - } - argc += i-1; - } - } - - return argc; -} - -static inline VALUE -vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, int num, - ID id, VALUE recv, VALUE klass, NODE *mn, rb_block_t *blockptr) -{ - VALUE val; - - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); - { - rb_control_frame_t *cfp = - vm_push_frame(th, 0, FRAME_MAGIC_CFUNC, - recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1); - - cfp->method_id = id; - cfp->method_klass = klass; - - reg_cfp->sp -= num + 1; - - val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1); - - if (reg_cfp != th->cfp + 1) { - rb_bug("cfp consistency error - send"); - } - vm_pop_frame(th); - } - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); - - return val; -} - -static inline VALUE -vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv, - VALUE klass, int argc, VALUE *argv) -{ - rb_control_frame_t *cfp = th->cfp; - rb_proc_t *proc; - VALUE val; - - /* control block frame */ - (cfp-2)->method_id = id; - (cfp-2)->method_klass = klass; - - GetProcPtr(procval, proc); - val = vm_invoke_proc(th, proc, recv, argc, argv); - return val; -} - -static inline VALUE -vm_method_missing(rb_thread_t *th, ID id, VALUE recv, int num, - rb_block_t *blockptr, int opt) -{ - rb_control_frame_t *reg_cfp = th->cfp; - VALUE *argv = STACK_ADDR_FROM_TOP(num + 1); - VALUE val; - argv[0] = ID2SYM(id); - th->method_missing_reason = opt; - th->passed_block = blockptr; - val = rb_funcall2(recv, idMethodMissing, num + 1, argv); - POPN(num + 1); - return val; -} - -static inline void -vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, - int argc, rb_block_t *blockptr, VALUE flag, - VALUE iseqval, VALUE recv, VALUE klass) -{ - rb_iseq_t *iseq; - int opt_pc, i; - VALUE *rsp = cfp->sp - argc; - VALUE *sp; - - /* TODO: eliminate it */ - GetISeqPtr(iseqval, iseq); - - opt_pc = vm_callee_setup_arg(th, iseq, argc, rsp, &blockptr); - sp = rsp + iseq->arg_size; - - /* stack overflow check */ - CHECK_STACK_OVERFLOW(cfp, iseq->stack_max + 0x10); - - if (flag & VM_CALL_TAILCALL_BIT) { - VALUE *p_rsp; - cfp = ++th->cfp; /* pop cf */ - p_rsp = th->cfp->sp; - - /* copy arguments */ - for (i=0; i < (sp - rsp); i++) { - p_rsp[i] = rsp[i]; - } - - sp -= rsp - p_rsp; - - /* clear local variables */ - for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { - *sp++ = Qnil; - } - - vm_push_frame(th, iseq, - FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, - iseq->iseq_encoded + opt_pc, sp, 0, 0); - } - else { - if (0) printf("local_size: %d, arg_size: %d\n", - iseq->local_size, iseq->arg_size); - - /* clear local variables */ - for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { - *sp++ = Qnil; - } - - vm_push_frame(th, iseq, - FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, - iseq->iseq_encoded + opt_pc, sp, 0, 0); - - cfp->sp = rsp - 1 /* recv */; - } -} - -static inline VALUE -vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, - int num, rb_block_t *blockptr, VALUE flag, - ID id, NODE *mn, VALUE recv, VALUE klass) -{ - VALUE val; - - start_method_dispatch: - - /* method missing */ - if (mn == 0) { - if (id == idMethodMissing) { - rb_bug("method missing"); - } - else { - int stat = 0; - if (flag & VM_CALL_VCALL_BIT) { - stat |= NOEX_VCALL; - } - if (flag & VM_CALL_SUPER_BIT) { - stat |= NOEX_SUPER; - } - val = vm_method_missing(th, id, recv, num, blockptr, stat); - } - } - else if (!(flag & VM_CALL_FCALL_BIT) && - (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) { - int stat = NOEX_PRIVATE; - if (flag & VM_CALL_VCALL_BIT) { - stat |= NOEX_VCALL; - } - val = vm_method_missing(th, id, recv, num, blockptr, stat); - } - else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) { - VALUE defined_class = mn->nd_clss; - - if (TYPE(defined_class) == T_ICLASS) { - defined_class = RBASIC(defined_class)->klass; - } - - if (!rb_obj_is_kind_of(cfp->self, rb_class_real(defined_class))) { - val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); - } - else { - goto normal_method_dispatch; - } - } - - /* dispatch method */ - else { - NODE *node; - normal_method_dispatch: - - node = mn->nd_body; - switch (nd_type(node)) { - case RUBY_VM_METHOD_NODE:{ - vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv, klass); - return Qundef; - } - case NODE_CFUNC:{ - val = vm_call_cfunc(th, cfp, num, id, recv, klass, node, blockptr); - break; - } - case NODE_ATTRSET:{ - val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1)); - cfp->sp -= 2; - break; - } - case NODE_IVAR:{ - val = rb_ivar_get(recv, node->nd_vid); - cfp->sp -= 1; - break; - } - case NODE_BMETHOD:{ - VALUE *argv = cfp->sp - num; - val = vm_call_bmethod(th, id, node->nd_cval, recv, klass, num, argv); - cfp->sp += - num - 1; - break; - } - case NODE_ZSUPER:{ - klass = RCLASS(mn->nd_clss)->super; - mn = rb_method_node(klass, id); - - if (mn != 0) { - goto normal_method_dispatch; - } - else { - goto start_method_dispatch; - } - } - default:{ - printf("node: %s\n", ruby_node_name(nd_type(node))); - rb_bug("eval_invoke_method: unreachable"); - /* unreachable */ - break; - } - } - } - - RUBY_VM_CHECK_INTS(); - return val; -} - /* Env */ @@ -697,7 +226,7 @@ vm_make_env_each(rb_thread_t *th, rb_control_frame_t *cfp, env->block.dfp = cfp->dfp; env->block.iseq = cfp->iseq; - if (VM_DEBUG && + if (VMDEBUG && (!(cfp->lfp[-1] == Qnil || BUILTIN_TYPE(cfp->lfp[-1]) == T_VALUES))) { rb_bug("illegal svar"); @@ -855,7 +384,7 @@ vm_make_proc(rb_thread_t *th, proc->safe_level = th->safe_level; proc->special_cref_stack = lfp_get_special_cref(block->lfp); - if (VM_DEBUG) { + if (VMDEBUG) { if (th->stack < block->dfp && block->dfp < th->stack + th->stack_size) { rb_bug("invalid ptr: block->dfp"); } @@ -1228,56 +757,6 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, return val; } -static struct RValues * -new_value(void) -{ - struct RValues *val = RVALUES(rb_newobj()); - OBJSETUP(val, 0, T_VALUES); - val->v1 = val->v2 = val->v3 = Qnil; - return val; -} - -static VALUE * -lfp_svar(VALUE *lfp, int cnt) -{ - struct RValues *val; - rb_thread_t *th = GET_THREAD(); - - if (th->local_lfp != lfp) { - val = (struct RValues *)lfp[-1]; - if ((VALUE)val == Qnil) { - val = new_value(); - lfp[-1] = (VALUE)val; - } - } - else { - val = (struct RValues *)th->local_svar; - if ((VALUE)val == Qnil) { - val = new_value(); - th->local_svar = (VALUE)val; - } - } - switch (cnt) { - case -1: - return &val->basic.klass; - case 0: - return &val->v1; - case 1: - return &val->v2; - default:{ - VALUE ary; - if ((ary = val->v3) == Qnil) { - ary = val->v3 = rb_ary_new(); - } - if (RARRAY_LEN(ary) <= cnt) { - rb_ary_store(ary, cnt, Qnil); - } - return &RARRAY_PTR(ary)[cnt]; - } - } -} - - VALUE * vm_cfp_svar(rb_control_frame_t *cfp, int cnt) { @@ -1423,60 +902,7 @@ thread_backtrace(VALUE self, int level) return vm_backtrace(th, level); } -/* - * vm main loop helper functions - */ - - -static NODE * -lfp_get_special_cref(VALUE *lfp) -{ - struct RValues *values; - if (((VALUE)(values = (void *)lfp[-1])) != Qnil && values->basic.klass) { - return (NODE *)values->basic.klass; - } - else { - return 0; - } -} - -static void -check_svar(void) -{ - rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = th->cfp; - while ((void *)(cfp + 1) < (void *)(th->stack + th->stack_size)) { - /* printf("cfp: %p\n", cfp->magic); */ - if (cfp->lfp && cfp->lfp[-1] != Qnil && - TYPE(cfp->lfp[-1]) != T_VALUES) { - /* dp(cfp->lfp[-1]); */ - rb_bug("!!!illegal svar!!!"); - } - cfp++; - } -} - -static NODE * -lfp_set_special_cref(VALUE *lfp, NODE * cref) -{ - struct RValues *values = (void *) lfp[-1]; - VALUE *pv; - NODE *old_cref; - - if (VM_DEBUG) { - check_svar(); - } - - if (cref == 0 && ((VALUE)values == Qnil || values->basic.klass == 0)) { - old_cref = 0; - } - else { - pv = lfp_svar(lfp, -1); - old_cref = (NODE *) * pv; - *pv = (VALUE)cref; - } - return old_cref; -} +/* cref */ NODE * vm_set_special_cref(rb_thread_t *th, VALUE *lfp, NODE * cref_stack) @@ -1484,6 +910,7 @@ vm_set_special_cref(rb_thread_t *th, VALUE *lfp, NODE * cref_stack) return lfp_set_special_cref(lfp, cref_stack); } +#if 0 void debug_cref(NODE *cref) { @@ -1493,22 +920,7 @@ debug_cref(NODE *cref) cref = cref->nd_next; } } - -static NODE * -get_cref(rb_iseq_t *iseq, VALUE *lfp) -{ - NODE *cref; - if ((cref = lfp_get_special_cref(lfp)) != 0) { - /* */ - } - else if ((cref = iseq->cref_stack) != 0) { - /* */ - } - else { - rb_bug("get_cref: unreachable"); - } - return cref; -} +#endif NODE * vm_get_cref(rb_thread_t *th, rb_iseq_t *iseq, rb_control_frame_t *cfp) @@ -1544,176 +956,6 @@ vm_get_cbase(rb_thread_t *th) return klass; } -static inline VALUE -vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq, - VALUE klass, ID id, int is_defined) -{ - VALUE val; - - if (klass == Qnil) { - /* in current lexical scope */ - NODE *root_cref = get_cref(iseq, th->cfp->lfp); - NODE *cref = root_cref; - - while (cref && cref->nd_next) { - klass = cref->nd_clss; - cref = cref->nd_next; - - if (klass == 0) { - continue; - } - if (NIL_P(klass)) { - if (is_defined) { - /* TODO: check */ - return 1; - } - else { - klass = CLASS_OF(th->cfp->self); - return rb_const_get(klass, id); - } - } - search_continue: - if (RCLASS(klass)->iv_tbl && - st_lookup(RCLASS(klass)->iv_tbl, id, &val)) { - if (val == Qundef) { - rb_autoload_load(klass, id); - goto search_continue; - } - else { - if (is_defined) { - return 1; - } - else { - return val; - } - } - } - } - klass = root_cref->nd_clss; - if (is_defined) { - return rb_const_defined(klass, id); - } - else { - return rb_const_get(klass, id); - } - } - else { - switch (TYPE(klass)) { - case T_CLASS: - case T_MODULE: - break; - default: - rb_raise(rb_eTypeError, "%s is not a class/module", - RSTRING_PTR(rb_obj_as_string(klass))); - } - if (is_defined) { - return rb_const_defined(klass, id); - } - else { - return rb_const_get(klass, id); - } - } -} - -static inline VALUE -vm_get_cvar_base(rb_thread_t *th, rb_iseq_t *iseq) -{ - NODE *cref = get_cref(iseq, th->cfp->lfp); - VALUE klass = Qnil; - - if (cref) { - klass = cref->nd_clss; - if (!cref->nd_next) { - rb_warn("class variable access from toplevel"); - } - } - if (NIL_P(klass)) { - rb_raise(rb_eTypeError, "no class variables available"); - } - return klass; -} - -static inline void -vm_define_method(rb_thread_t *th, VALUE obj, - ID id, rb_iseq_t *miseq, rb_num_t is_singleton, NODE *cref) -{ - NODE *newbody; - int noex = cref->nd_visi; - VALUE klass = cref->nd_clss; - - if (is_singleton) { - if (FIXNUM_P(obj) || SYMBOL_P(obj)) { - rb_raise(rb_eTypeError, - "can't define singleton method \"%s\" for %s", - rb_id2name(id), rb_obj_classname(obj)); - } - - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } - - klass = rb_singleton_class(obj); - noex = NOEX_PUBLIC; - } - - /* dup */ - COPY_CREF(miseq->cref_stack, cref); - miseq->klass = klass; - miseq->defined_method_id = id; - newbody = NEW_NODE(RUBY_VM_METHOD_NODE, 0, miseq->self, 0); - rb_add_method(klass, id, newbody, noex); - - if (!is_singleton && noex == NOEX_MODFUNC) { - rb_add_method(rb_singleton_class(klass), id, newbody, NOEX_PUBLIC); - } - INC_VM_STATE_VERSION(); -} - -static inline NODE * -vm_method_search(VALUE id, VALUE klass, IC ic) -{ - NODE *mn; - -#if OPT_INLINE_METHOD_CACHE - { - if (LIKELY(klass == ic->ic_klass) && - LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) { - mn = ic->ic_method; - } - else { - mn = rb_method_node(klass, id); - ic->ic_klass = klass; - ic->ic_method = mn; - ic->ic_vmstat = GET_VM_STATE_VERSION(); - } - } -#else - mn = rb_method_node(klass, id); -#endif - return mn; -} - -static inline int -block_proc_is_lambda(VALUE procval) -{ - rb_proc_t *proc; - - if (procval) { - GetProcPtr(procval, proc); - return proc->is_lambda; - } - else { - return 0; - } -} - -static void -call_yarv_end_proc(VALUE data) -{ - rb_proc_call(data, rb_ary_new2(0)); -} - - /*********************************************************/ /*********************************************************/ @@ -1809,7 +1051,7 @@ vm_iter_break(rb_thread_t *th) TH_JUMP_TAG(th, TAG_BREAK); } -static VALUE yarv_redefined_flag = 0; +VALUE ruby_vm_redefined_flag = 0; static st_table *vm_opt_method_table = 0; void @@ -1818,7 +1060,7 @@ rb_vm_check_redefinition_opt_method(NODE *node) VALUE bop; if (st_lookup(vm_opt_method_table, (st_data_t)node, &bop)) { - yarv_redefined_flag |= bop; + ruby_vm_redefined_flag |= bop; } } diff --git a/vm.h b/vm.h index 457922ceba..e3e5ddd8c2 100644 --- a/vm.h +++ b/vm.h @@ -13,13 +13,21 @@ #ifndef _VM_H_INCLUDED_ #define _VM_H_INCLUDED_ - #if YARVDEBUG > VMDEBUG #undef VMDEBUG #define VMDEBUG YARVDEBUG #endif typedef long OFFSET; +typedef unsigned long rb_num_t; +typedef unsigned long lindex_t; +typedef unsigned long dindex_t; +typedef rb_num_t GENTRY; + +extern VALUE rb_cEnv; +extern VALUE ruby_vm_global_state_version; +extern VALUE ruby_vm_redefined_flag; + /** * VM Debug Level @@ -167,7 +175,6 @@ typedef rb_control_frame_t * #endif /* DISPATCH_DIRECT_THREADED_CODE */ #define END_INSN(insn) \ - GC_CHECK(); \ DEBUG_END_INSN(); \ TC_DISPATCH(insn); \ @@ -189,7 +196,6 @@ typedef rb_control_frame_t * case BIN(insn): #define END_INSN(insn) \ - GC_CHECK(); \ DEBUG_END_INSN(); \ break; @@ -266,9 +272,9 @@ default: \ /* VM state version */ -#define GET_VM_STATE_VERSION() (vm_global_state_version) +#define GET_VM_STATE_VERSION() (ruby_vm_global_state_version) #define INC_VM_STATE_VERSION() \ - (vm_global_state_version = (vm_global_state_version+1) & 0x8fffffff) + (ruby_vm_global_state_version = (ruby_vm_global_state_version+1) & 0x8fffffff) #define BOP_PLUS 0x01 #define BOP_MINUS 0x02 diff --git a/vm_dump.c b/vm_dump.c index 5030466b45..76b63bd203 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -399,10 +399,6 @@ debug_print_post(rb_thread_t *th, rb_control_frame_t *cfp printf ("--------------------------------------------------------------\n"); #endif - -#if VMDEBUG > 9 - GC_CHECK(); -#endif } #ifdef COLLECT_USAGE_ANALYSIS -- cgit v1.2.3