From a9ccdcf68119e5d445aedecefd311b52c9b5e3c7 Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 1 Feb 2009 22:36:15 +0000 Subject: * 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: http://svn.ruby-lang.org/repos/ruby/trunk@21932 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm.c | 67 ++++++++++++++++++++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) (limited to 'vm.c') diff --git a/vm.c b/vm.c index a549f0280..daed3bc6c 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 * -- cgit