From a7b5c603b4747704d8ed7ce22c342649e88f6993 Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 1 Feb 2009 22:36:15 +0000 Subject: [PATCH] * vm.c (vm_backtrace_each): now takes an iterator function. * vm_core.h (rb_make_backtrace, rb_backtrace_each): added prototypes. * vm_dump.c (rb_vm_bugreport), vm_eval.c (rb_backtrace): gets rid of allocating objects. * vm_eval.c (rb_backtrace_each): new function which iterates over each backtrace info. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21932 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 13 +++++++++++ eval.c | 1 - vm.c | 67 ++++++++++++++++++++++++++----------------------------- vm_core.h | 3 +++ vm_dump.c | 27 +++++++++++----------- vm_eval.c | 22 ++++++++++++------ 6 files changed, 76 insertions(+), 57 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52811c0c66..c4f5bc60cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Mon Feb 2 07:36:13 2009 Nobuyoshi Nakada + + * vm.c (vm_backtrace_each): now takes an iterator function. + + * vm_core.h (rb_make_backtrace, rb_backtrace_each): added + prototypes. + + * vm_dump.c (rb_vm_bugreport), vm_eval.c (rb_backtrace): gets rid + of allocating objects. + + * vm_eval.c (rb_backtrace_each): new function which iterates over + each backtrace info. + Mon Feb 2 06:51:36 2009 NAKAMURA Usaku * encoding.c (rb_filesystem_encoding): Windows' filesystem encoding is diff --git a/eval.c b/eval.c index c9aaa1dc84..603504ef4a 100644 --- a/eval.c +++ b/eval.c @@ -330,7 +330,6 @@ rb_frozen_class_p(VALUE klass) } NORETURN(static void rb_longjmp(int, VALUE)); -VALUE rb_make_backtrace(void); static void rb_longjmp(int tag, VALUE mesg) diff --git a/vm.c b/vm.c index a549f0280d..daed3bc6c3 100644 --- a/vm.c +++ b/vm.c @@ -687,62 +687,59 @@ rb_vm_get_sourceline(const rb_control_frame_t *cfp) return line_no; } -static VALUE -vm_backtrace_each(rb_thread_t *th, - const rb_control_frame_t *limit_cfp, const rb_control_frame_t *cfp, - const char * file, int line_no, VALUE ary) +static int +vm_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *arg) { - VALUE str; + const rb_control_frame_t *limit_cfp = th->cfp; + const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size); + const char *file; + int line_no = 0; + cfp -= 2; + while (lev-- >= 0) { + if (++limit_cfp >= cfp) { + return Qfalse; + } + } + limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp); + file = RSTRING_PTR(th->vm->progname); while (cfp > limit_cfp) { - str = 0; if (cfp->iseq != 0) { if (cfp->pc != 0) { rb_iseq_t *iseq = cfp->iseq; line_no = rb_vm_get_sourceline(cfp); file = RSTRING_PTR(iseq->filename); - str = rb_sprintf("%s:%d:in `%s'", - file, line_no, RSTRING_PTR(iseq->name)); - rb_ary_push(ary, str); + if ((*iter)(arg, file, line_no, RSTRING_PTR(iseq->name))) break; } } else if (RUBYVM_CFUNC_FRAME_P(cfp)) { - str = rb_sprintf("%s:%d:in `%s'", - file, line_no, - rb_id2name(cfp->method_id)); - rb_ary_push(ary, str); + if ((*iter)(arg, file, line_no, rb_id2name(cfp->method_id))) break; } cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp); } - return rb_ary_reverse(ary); + return Qtrue; +} + +static int +vm_backtrace_push(void *arg, const char *file, int line_no, const char *name) +{ + VALUE *aryp = arg; + if (!*aryp) { + *aryp = rb_ary_new(); + } + rb_ary_push(*aryp, rb_sprintf("%s:%d:in `%s'", file, line_no, name)); + return 0; } static inline VALUE vm_backtrace(rb_thread_t *th, int lev) { - VALUE ary; - const rb_control_frame_t *cfp = th->cfp; - const rb_control_frame_t *top_of_cfp = (void *)(th->stack + th->stack_size); - top_of_cfp -= 2; + VALUE ary = 0; - if (lev < 0) { - /* TODO ?? */ - ary = rb_ary_new(); - } - else { - while (lev-- >= 0) { - cfp++; - if (cfp >= top_of_cfp) { - return Qnil; - } - } - ary = rb_ary_new(); - } - - ary = vm_backtrace_each(th, RUBY_VM_NEXT_CONTROL_FRAME(cfp), - top_of_cfp, RSTRING_PTR(th->vm->progname), 0, ary); - return ary; + vm_backtrace_each(th, lev, vm_backtrace_push, &ary); + if (!ary) return Qnil; + return rb_ary_reverse(ary); } const char * diff --git a/vm_core.h b/vm_core.h index 68f83ff169..4d6ddcc64f 100644 --- a/vm_core.h +++ b/vm_core.h @@ -590,6 +590,9 @@ VALUE rb_vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp); void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1); int ruby_thread_has_gvl_p(void); +VALUE rb_make_backtrace(void); +typedef int rb_backtrace_iter_func(void *, const char *, int, const char *); +VALUE rb_backtrace_each(rb_backtrace_iter_func *iter, void *arg); NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); diff --git a/vm_dump.c b/vm_dump.c index 5bfd38284f..0a56d8169c 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -564,28 +564,27 @@ rb_vmdebug_thread_dump_state(VALUE self) return Qnil; } -VALUE rb_make_backtrace(void); +static int +bugreport_backtrace(void *arg, const char *file, int line, const char *method) +{ + if (!*(int *)arg) { + fprintf(stderr, "-- Ruby level backtrace information" + "-----------------------------------------\n"); + *(int *)arg = 1; + } + fprintf(stderr, "%s:%d:in `%s'\n", file, line, method); + return 0; +} void rb_vm_bugreport(void) { - VALUE bt; - if (GET_THREAD()->vm) { int i; SDR(); - bt = rb_make_backtrace(); - - if (bt) { - fprintf(stderr, "-- Ruby level backtrace information" - "-----------------------------------------\n"); - - for (i = 0; i < RARRAY_LEN(bt); i++) { - VALUE str = RARRAY_PTR(bt)[i]; - fprintf(stderr, "%s\n", RSTRING_PTR(str)); - } - fprintf(stderr, "\n"); + if (rb_backtrace_each(bugreport_backtrace, &i)) { + fputs("\n", stderr); } } diff --git a/vm_eval.c b/vm_eval.c index e9774d2785..ed0e34a6cd 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -16,6 +16,7 @@ static inline VALUE rb_vm_set_finish_env(rb_thread_t * th); static inline VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref); static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv); static inline VALUE vm_backtrace(rb_thread_t *th, int lev); +static int vm_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *arg); static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex); static VALUE vm_exec(rb_thread_t *th); static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref); @@ -1304,16 +1305,17 @@ rb_f_caller(int argc, VALUE *argv) return vm_backtrace(GET_THREAD(), lev); } +static int +print_backtrace(void *arg, const char *file, int line, const char *method) +{ + fprintf((FILE *)arg, "\tfrom %s:%d:in `%s'\n", file, line, method); + return Qfalse; +} + void rb_backtrace(void) { - long i; - VALUE ary; - - ary = vm_backtrace(GET_THREAD(), -1); - for (i = 0; i < RARRAY_LEN(ary); i++) { - printf("\tfrom %s\n", RSTRING_PTR(RARRAY_PTR(ary)[i])); - } + vm_backtrace_each(GET_THREAD(), -1, print_backtrace, stdout); } VALUE @@ -1322,6 +1324,12 @@ rb_make_backtrace(void) return vm_backtrace(GET_THREAD(), -1); } +VALUE +rb_backtrace_each(rb_backtrace_iter_func *iter, void *arg) +{ + return vm_backtrace_each(GET_THREAD(), -1, iter, arg); +} + /* * call-seq: * local_variables => array