[前][次][番号順一覧][スレッド一覧]

ruby-changes:23817

From: ko1 <ko1@a...>
Date: Sun, 3 Jun 2012 00:23:46 +0900 (JST)
Subject: [ruby-changes:23817] ko1:r35868 (trunk): * vm_backtrace.c: added. Separate backtrace related functions to

ko1	2012-06-03 00:23:37 +0900 (Sun, 03 Jun 2012)

  New Revision: 35868

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35868

  Log:
    * vm_backtrace.c: added.  Separate backtrace related functions to
      this file.
    * vm.c, common.mk: ditto.

  Added files:
    trunk/vm_backtrace.c
  Modified files:
    trunk/ChangeLog
    trunk/common.mk
    trunk/vm.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35867)
+++ ChangeLog	(revision 35868)
@@ -1,3 +1,10 @@
+Sun Jun  3 00:20:53 2012  Koichi Sasada  <ko1@a...>
+
+	* vm_backtrace.c: added.  Separate backtrace related functions to
+	  this file.
+
+	* vm.c, common.mk: ditto.
+
 Sat Jun  2 18:09:02 2012  Akinori MUSHA  <knu@i...>
 
 	* lib/ipaddr.rb: Inhibit zero-filled octets in an IPv4 address in
Index: common.mk
===================================================================
--- common.mk	(revision 35867)
+++ common.mk	(revision 35868)
@@ -752,7 +752,7 @@
   {$(VPATH)}vm_insnhelper.c {$(VPATH)}vm_insnhelper.h {$(VPATH)}vm_exec.c \
   {$(VPATH)}vm_exec.h {$(VPATH)}insns.def {$(VPATH)}vmtc.inc \
   {$(VPATH)}vm.inc {$(VPATH)}insns.inc {$(VPATH)}debug.h \
-  {$(VPATH)}internal.h {$(VPATH)}vm.h {$(VPATH)}constant.h
+  {$(VPATH)}internal.h {$(VPATH)}vm.h {$(VPATH)}constant.h {$(VPATH)}vm_backtrace.c
 vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c $(RUBY_H_INCLUDES) \
   $(VM_CORE_H_INCLUDES) {$(VPATH)}debug.h {$(VPATH)}addr2line.h
 debug.$(OBJEXT): {$(VPATH)}debug.c $(RUBY_H_INCLUDES) \
Index: vm_backtrace.c
===================================================================
--- vm_backtrace.c	(revision 0)
+++ vm_backtrace.c	(revision 35868)
@@ -0,0 +1,725 @@
+/**********************************************************************
+
+  vm_backtrace.c - 
+
+  $Author: ko1 $
+  created at: Sun Jun 03 00:14:20 2012
+
+  Copyright (C) 1993-2012 Yukihiro Matsumoto
+
+**********************************************************************/
+
+/* this file is included by vm.c */
+
+static VALUE rb_cBacktrace;
+static VALUE rb_cFrameInfo;
+
+extern VALUE ruby_engine_name;
+
+inline static int
+calc_line_no(const rb_iseq_t *iseq, const VALUE *pc)
+{
+    return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
+}
+
+int
+rb_vm_get_sourceline(const rb_control_frame_t *cfp)
+{
+    int line_no = 0;
+    const rb_iseq_t *iseq = cfp->iseq;
+
+    if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
+	line_no = calc_line_no(cfp->iseq, cfp->pc);
+    }
+    return line_no;
+}
+
+typedef struct rb_frame_info_struct {
+    enum FRAME_INFO_TYPE {
+	FRAME_INFO_TYPE_ISEQ = 1,
+	FRAME_INFO_TYPE_ISEQ_CALCED,
+	FRAME_INFO_TYPE_CFUNC,
+	FRAME_INFO_TYPE_IFUNC,
+    } type;
+
+    union {
+	struct {
+	    const rb_iseq_t *iseq;
+	    union {
+		const VALUE *pc;
+		int line_no;
+	    } line_no;
+	} iseq;
+	struct {
+	    ID mid;
+	    struct rb_frame_info_struct *prev_fi;
+	} cfunc;
+    } body;
+} rb_frame_info_t;
+
+struct valued_frame_info {
+    rb_frame_info_t *fi;
+    VALUE btobj;
+};
+
+static void
+frame_info_mark(void *ptr)
+{
+    if (ptr) {
+	struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
+	rb_gc_mark(vfi->btobj);
+    }
+}
+
+static void
+frame_info_mark_entry(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	rb_gc_mark(fi->body.iseq.iseq->self);
+	break;
+      case FRAME_INFO_TYPE_CFUNC:
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	break;
+    }
+}
+
+static void
+frame_info_free(void *ptr)
+{
+    if (ptr) {
+	rb_frame_info_t *fi = (rb_frame_info_t *)ptr;
+	ruby_xfree(fi);
+    }
+}
+
+static size_t
+frame_info_memsize(const void *ptr)
+{
+    /* rb_frame_info_t *fi = (rb_frame_info_t *)ptr; */
+    return sizeof(rb_frame_info_t);
+}
+
+static const rb_data_type_t frame_info_data_type = {
+    "frame_info",
+    {frame_info_mark, frame_info_free, frame_info_memsize,},
+};
+
+static inline rb_frame_info_t *
+frame_info_ptr(VALUE fiobj)
+{
+    struct valued_frame_info *vfi;
+    GetCoreDataFromValue(fiobj, struct valued_frame_info, vfi);
+    return vfi->fi;
+}
+
+static int
+frame_info_line_no(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+	fi->type = FRAME_INFO_TYPE_ISEQ_CALCED;
+	return (fi->body.iseq.line_no.line_no = calc_line_no(fi->body.iseq.iseq, fi->body.iseq.line_no.pc));
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.line_no.line_no;
+      case FRAME_INFO_TYPE_CFUNC:
+	if (fi->body.cfunc.prev_fi) {
+	    return frame_info_line_no(fi->body.cfunc.prev_fi);
+	}
+	return 0;
+      default:
+	rb_bug("frame_info_line_no: unreachable");
+	UNREACHABLE;
+    }
+}
+
+static VALUE
+frame_info_line_no_m(VALUE self)
+{
+    return INT2FIX(frame_info_line_no(frame_info_ptr(self)));
+}
+
+static VALUE
+frame_info_name(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.iseq->location.name;
+      case FRAME_INFO_TYPE_CFUNC:
+	return rb_id2str(fi->body.cfunc.mid);
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	rb_bug("frame_info_name: unreachable");
+	UNREACHABLE;
+    }
+}
+
+static VALUE
+frame_info_name_m(VALUE self)
+{
+    return frame_info_name(frame_info_ptr(self));
+}
+
+static VALUE
+frame_info_basename(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.iseq->location.basename;
+      case FRAME_INFO_TYPE_CFUNC:
+	return rb_sym_to_s(ID2SYM(fi->body.cfunc.mid));
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	rb_bug("frame_info_basename: unreachable");
+	UNREACHABLE;
+    }
+}
+
+static VALUE
+frame_info_basename_m(VALUE self)
+{
+    return frame_info_basename(frame_info_ptr(self));
+}
+
+static VALUE
+frame_info_filename(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.iseq->location.filename;
+      case FRAME_INFO_TYPE_CFUNC:
+	if (fi->body.cfunc.prev_fi) {
+	    return frame_info_filename(fi->body.cfunc.prev_fi);
+	}
+	return Qnil;
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	rb_bug("frame_info_filename: unreachable");
+	UNREACHABLE;
+    }
+}
+
+static VALUE
+frame_info_filename_m(VALUE self)
+{
+    return frame_info_filename(frame_info_ptr(self));
+}
+
+static VALUE
+frame_info_filepath(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.iseq->location.filepath;
+      case FRAME_INFO_TYPE_CFUNC:
+	if (fi->body.cfunc.prev_fi) {
+	    return frame_info_filepath(fi->body.cfunc.prev_fi);
+	}
+	return Qnil;
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	rb_bug("frame_info_filepath: unreachable");
+	UNREACHABLE;
+    }
+}
+
+static VALUE
+frame_info_filepath_m(VALUE self)
+{
+    return frame_info_filepath(frame_info_ptr(self));
+}
+
+static VALUE
+frame_info_iseq(rb_frame_info_t *fi)
+{
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	return fi->body.iseq.iseq->self;
+      default:
+	return Qnil;
+    }
+}
+
+static VALUE
+frame_info_iseq_m(VALUE self)
+{
+    return frame_info_iseq(frame_info_ptr(self));
+}
+
+static VALUE
+frame_info_format(VALUE file, int line_no, VALUE name)
+{
+    if (line_no != 0) {
+	return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
+			      RSTRING_PTR(file), line_no, RSTRING_PTR(name));
+    }
+    else {
+	return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
+			      RSTRING_PTR(file), RSTRING_PTR(name));
+    }
+}
+
+static VALUE
+frame_info_to_str(rb_frame_info_t *fi)
+{
+    VALUE file, name;
+    int line_no;
+
+    switch (fi->type) {
+      case FRAME_INFO_TYPE_ISEQ:
+	file = fi->body.iseq.iseq->location.filename;
+	name = fi->body.iseq.iseq->location.name;
+
+	line_no = fi->body.iseq.line_no.line_no = calc_line_no(fi->body.iseq.iseq, fi->body.iseq.line_no.pc);
+	fi->type = FRAME_INFO_TYPE_ISEQ_CALCED;
+	break;
+      case FRAME_INFO_TYPE_ISEQ_CALCED:
+	file = fi->body.iseq.iseq->location.filename;
+	line_no = fi->body.iseq.line_no.line_no;
+	name = fi->body.iseq.iseq->location.name;
+	break;
+      case FRAME_INFO_TYPE_CFUNC:
+	if (fi->body.cfunc.prev_fi) {
+	    file = fi->body.cfunc.prev_fi->body.iseq.iseq->location.filename;
+	    line_no = frame_info_line_no(fi->body.cfunc.prev_fi);
+	}
+	else {
+	    rb_thread_t *th = GET_THREAD();
+	    file = th->vm->progname ? th->vm->progname : ruby_engine_name;
+	    line_no = INT2FIX(0);
+	}
+	name = rb_id2str(fi->body.cfunc.mid);
+	break;
+      case FRAME_INFO_TYPE_IFUNC:
+      default:
+	rb_bug("frame_info_to_str: unreachable");
+    }
+
+    return frame_info_format(file, line_no, name);
+}
+
+static VALUE
+frame_info_to_str_m(VALUE self)
+{
+    return frame_info_to_str(frame_info_ptr(self));
+}
+
+typedef struct rb_backtrace_struct {
+    rb_frame_info_t *backtrace;
+    rb_frame_info_t *backtrace_base;
+    int backtrace_size;
+    VALUE strary;
+} rb_backtrace_t;
+
+static void
+backtrace_mark(void *ptr)
+{
+    if (ptr) {
+	rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+	size_t i, s = bt->backtrace_size;
+
+	for (i=0; i<s; i++) {
+	    frame_info_mark_entry(&bt->backtrace[i]);
+	    rb_gc_mark(bt->strary);
+	}
+    }
+}
+
+static void
+backtrace_free(void *ptr)
+{
+   if (ptr) {
+       rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+       if (bt->backtrace) ruby_xfree(bt->backtrace_base);
+       ruby_xfree(bt);
+   }
+}
+
+static size_t
+backtrace_memsize(const void *ptr)
+{
+    rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+    return sizeof(rb_backtrace_t) + sizeof(rb_frame_info_t) * bt->backtrace_size;
+}
+
+static const rb_data_type_t backtrace_data_type = {
+    "backtrace",
+    {backtrace_mark, backtrace_free, backtrace_memsize,},
+};
+
+int
+rb_backtrace_p(VALUE obj)
+{
+    return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
+}
+
+static VALUE
+backtrace_alloc(VALUE klass)
+{
+    rb_backtrace_t *bt;
+    VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
+    return obj;
+}
+
+static void
+backtrace_each(rb_thread_t *th,
+	       void (*init)(void *arg, size_t size),
+	       void (*iter_iseq)(void *arg, const rb_iseq_t *iseq, const VALUE *pc),
+	       void (*iter_cfunc)(void *arg, ID mid),
+	       void *arg)
+{
+    rb_control_frame_t *last_cfp = th->cfp;
+    rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th);
+    rb_control_frame_t *cfp;
+    ptrdiff_t size, i;
+
+    /*                <- start_cfp (end control frame)
+     *  top frame (dummy)
+     *  top frame (dummy)
+     *  top frame     <- start_cfp
+     *  top frame
+     *  ...
+     *  2nd frame     <- lev:0
+     *  current frame <- th->cfp
+     */
+
+    start_cfp =
+      RUBY_VM_NEXT_CONTROL_FRAME(
+	  RUBY_VM_NEXT_CONTROL_FRAME(
+	      RUBY_VM_NEXT_CONTROL_FRAME(start_cfp))); /* skip top frames */
+
+    if (start_cfp < last_cfp) {
+	size = 0;
+    }
+    else {
+	size = start_cfp - last_cfp + 1;
+    }
+
+    init(arg, size);
+
+    /* SDR(); */
+    for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+	/* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */
+	if (cfp->iseq) {
+	    if (cfp->pc) {
+		iter_iseq(arg, cfp->iseq, cfp->pc);
+	    }
+	}
+	else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
+	    ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
+
+	    if (mid != ID_ALLOCATOR) {
+		iter_cfunc(arg, mid);
+	    }
+	}
+    }
+}
+
+struct bt_iter_arg {
+    rb_backtrace_t *bt;
+    VALUE btobj;
+    rb_frame_info_t *prev_fi;
+};
+
+static void
+bt_init(void *ptr, size_t size)
+{
+    struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
+    arg->btobj = backtrace_alloc(rb_cBacktrace);
+    GetCoreDataFromValue(arg->btobj, rb_backtrace_t, arg->bt);
+    arg->bt->backtrace_base = arg->bt->backtrace = ruby_xmalloc(sizeof(rb_frame_info_t) * size);
+    arg->bt->backtrace_size = 0;
+}
+
+static void
+bt_iter_iseq(void *ptr, const rb_iseq_t *iseq, const VALUE *pc)
+{
+    struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
+    rb_frame_info_t *fi = &arg->bt->backtrace[arg->bt->backtrace_size++];
+    fi->type = FRAME_INFO_TYPE_ISEQ;
+    fi->body.iseq.iseq = iseq;
+    fi->body.iseq.line_no.pc = pc;
+    arg->prev_fi = fi;
+}
+
+static void
+bt_iter_cfunc(void *ptr, ID mid)
+{
+    struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
+    rb_frame_info_t *fi = &arg->bt->backtrace[arg->bt->backtrace_size++];
+    fi->type = FRAME_INFO_TYPE_CFUNC;
+    fi->body.cfunc.mid = mid;
+    fi->body.cfunc.prev_fi = arg->prev_fi;
+}
+
+static VALUE
+backtrace_object(rb_thread_t *th)
+{
+    struct bt_iter_arg arg;
+    arg.prev_fi = 0;
+
+    backtrace_each(th,
+		   bt_init,
+		   bt_iter_iseq,
+		   bt_iter_cfunc,
+		   &arg);
+
+    return arg.btobj;
+}
+
+VALUE
+rb_vm_backtrace_object(void)
+{
+    return backtrace_object(GET_THREAD());
+}
+
+static VALUE
+backtreace_collect(rb_backtrace_t *bt, int lev, int n, VALUE (*func)(rb_frame_info_t *, void *arg), void *arg)
+{
+    VALUE btary;
+    int i;
+
+    if (UNLIKELY(lev < 0 || n < 0)) {
+	rb_bug("backtreace_collect: unreachable");
+    }
+
+    btary = rb_ary_new();
+
+    for (i=0; i+lev<bt->backtrace_size && i<n; i++) {
+	rb_frame_info_t *fi = &bt->backtrace[bt->backtrace_size - 1 - (lev+i)];
+	rb_ary_push(btary, func(fi, arg));
+    }
+
+    return btary;
+}
+
+static VALUE
+frame_info_to_str_dmyarg(rb_frame_info_t *fi, void *dmy)
+{
+    return frame_info_to_str(fi);
+}
+
+VALUE
+rb_backtrace_to_str_ary(VALUE self)
+{
+    rb_backtrace_t *bt;
+    GetCoreDataFromValue(self, rb_backtrace_t, bt);
+
+    if (bt->strary) {
+	return bt->strary;
+    }
+    else {
+	bt->strary = backtreace_collect(bt, 0, bt->backtrace_size, frame_info_to_str_dmyarg, 0);
+	return bt->strary;
+    }
+}
+
+static VALUE
+backtrace_to_str_ary2(VALUE self, int lev, int n)
+{
+    rb_backtrace_t *bt;
+    int size;
+    GetCoreDataFromValue(self, rb_backtrace_t, bt);
+    size = bt->backtrace_size;
+
+    if (n == 0) {
+	n = size;
+    }
+    if (lev > size) {
+	return Qnil;
+    }
+
+    return backtreace_collect(bt, lev, n, frame_info_to_str_dmyarg, 0);
+}
+
+static VALUE
+frame_info_create(rb_frame_info_t *srcfi, void *btobj)
+{
+    VALUE obj;
+    struct valued_frame_info *vfi;
+    obj = TypedData_Make_Struct(rb_cFrameInfo, struct valued_frame_info, &frame_info_data_type, vfi);
+
+    vfi->fi = srcfi;
+    vfi->btobj = (VALUE)btobj;
+
+    return obj;
+}
+
+static VALUE
+backtrace_to_frame_ary(VALUE self, int lev, int n)
+{
+    rb_backtrace_t *bt;
+    int size;
+    GetCoreDataFromValue(self, rb_backtrace_t, bt);
+    size = bt->backtrace_size;
+
+    if (n == 0) {
+	n = size;
+    }
+    if (lev > size) {
+	return Qnil;
+    }
+
+    return backtreace_collect(bt, lev, n, frame_info_create, (void *)self);
+}
+
+static VALUE
+backtrace_dump_data(VALUE self)
+{
+    VALUE str = rb_backtrace_to_str_ary(self);
+    return str;
+}
+
+static VALUE
+backtrace_load_data(VALUE self, VALUE str)
+{
+    rb_backtrace_t *bt;
+    GetCoreDataFromValue(self, rb_backtrace_t, bt);
+    bt->strary = str;
+    return self;
+}
+
+static VALUE
+vm_backtrace_str_ary(rb_thread_t *th, int lev, int n)
+{
+    return backtrace_to_str_ary2(backtrace_object(th), lev, n);
+}
+
+static VALUE
+vm_backtrace_frame_ary(rb_thread_t *th, int lev, int n)
+{
+    return backtrace_to_frame_ary(backtrace_object(th), lev, n);
+}
+
+/* old style backtrace directly */
+
+struct oldbt_arg {
+    VALUE filename;
+    int line_no;
+    void (*func)(void *data, VALUE file, int line_no, VALUE name);
+    void *data; /* result */
+};
+
+static void
+oldbt_init(void *ptr, size_t dmy)
+{
+    struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
+    rb_thread_t *th = GET_THREAD();
+
+    arg->filename = th->vm->progname ? th->vm->progname : ruby_engine_name;;
+    arg->line_no = 0;
+}
+
+static void
+oldbt_iter_iseq(void *ptr, const rb_iseq_t *iseq, const VALUE *pc)
+{
+    struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
+    VALUE file = arg->filename = iseq->location.filename;
+    VALUE name = iseq->location.name;
+    int line_no = arg->line_no = calc_line_no(iseq, pc);
+
+    (arg->func)(arg->data, file, line_no, name);
+}
+
+static void
+oldbt_iter_cfunc(void *ptr, ID mid)
+{
+    struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
+    VALUE file = arg->filename;
+    VALUE name = rb_id2str(mid);
+    int line_no = arg->line_no;
+
+    (arg->func)(arg->data, file, line_no, name);
+}
+
+static void
+oldbt_print(void *data, VALUE file, int line_no, VALUE name)
+{
+    FILE *fp = (FILE *)data;
+
+    if (NIL_P(name)) {
+	fprintf(fp, "\tfrom %s:%d:in unknown method\n",
+		RSTRING_PTR(file), line_no);
+    }
+    else {
+	fprintf(fp, "\tfrom %s:%d:in `%s'\n",
+		RSTRING_PTR(file), line_no, RSTRING_PTR(name));
+    }
+}
+
+static void
+vm_backtrace_print(FILE *fp)
+{
+    struct oldbt_arg arg;
+
+    arg.func = oldbt_print;
+    arg.data = (void *)fp;
+    backtrace_each(GET_THREAD(),
+		   oldbt_init,
+		   oldbt_iter_iseq,
+		   oldbt_iter_cfunc,
+		   &arg);
+}
+
+static void
+oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
+{
+    const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
+    if (!*(int *)arg) {
+	fprintf(stderr, "-- Ruby level backtrace information "
+		"----------------------------------------\n");
+	*(int *)arg = 1;
+    }
+    if (NIL_P(method)) {
+	fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
+    }
+    else {
+	fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
+    }
+}
+
+void
+rb_backtrace_print_as_bugreport(void)
+{
+    struct oldbt_arg arg;
+    int i;
+
+    arg.func = oldbt_bugreport;
+    arg.data = (int *)&i;
+
+    backtrace_each(GET_THREAD(),
+		   oldbt_init,
+		   oldbt_iter_iseq,
+		   oldbt_iter_cfunc,
+		   &arg);
+}
+
+static void
+Init_vm_backtrace(void)
+{
+    /* ::RubyVM::Backtrace */
+    rb_cBacktrace = rb_define_class_under(rb_cRubyVM, "Backtrace", rb_cObject);
+    rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
+    rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
+    rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
+
+    /* ::RubyVM::FrameInfo */
+    rb_cFrameInfo = rb_define_class_under(rb_cRubyVM, "FrameInfo", rb_cObject);
+    rb_undef_alloc_func(rb_cFrameInfo);
+    rb_undef_method(CLASS_OF(rb_cFrameInfo), "new");
+    rb_define_method(rb_cFrameInfo, "line_no", frame_info_line_no_m, 0);
+    rb_define_method(rb_cFrameInfo, "name", frame_info_name_m, 0);
+    rb_define_method(rb_cFrameInfo, "basename", frame_info_basename_m, 0);
+    rb_define_method(rb_cFrameInfo, "filename", frame_info_filename_m, 0);
+    rb_define_method(rb_cFrameInfo, "filepath", frame_info_filepath_m, 0);
+    rb_define_method(rb_cFrameInfo, "iseq", frame_info_iseq_m, 0);
+    rb_define_method(rb_cFrameInfo, "to_s", frame_info_to_str_m, 0);
+    rb_define_singleton_method(rb_cFrameInfo, "caller", rb_f_caller_frame_info, -1);
+}
Index: vm.c
===================================================================
--- vm.c	(revision 35867)
+++ vm.c	(revision 35868)
@@ -26,6 +26,7 @@
 
 #include "vm_method.c"
 #include "vm_eval.c"
+#include "vm_backtrace.c"
 
 #include <assert.h>
 
@@ -36,16 +37,12 @@
 VALUE rb_cThread;
 VALUE rb_cEnv;
 VALUE rb_mRubyVMFrozenCore;
-static VALUE rb_cBacktrace;
-static VALUE rb_cFrameInfo;
 
 VALUE ruby_vm_const_missing_count = 0;
 char ruby_vm_redefined_flag[BOP_LAST_];
 rb_thread_t *ruby_current_thread = 0;
 rb_vm_t *ruby_current_vm = 0;
 
-extern VALUE ruby_engine_name;
-
 static void thread_free(void *ptr);
 
 void vm_analysis_operand(int insn, int n, VALUE op);
@@ -731,693 +728,6 @@
     vm_svar_set(0, val);
 }
 
-/* backtrace */
-
-inline static int
-calc_line_no(const rb_iseq_t *iseq, const VALUE *pc)
-{
-    return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
-}
-
-int
-rb_vm_get_sourceline(const rb_control_frame_t *cfp)
-{
-    int line_no = 0;
-    const rb_iseq_t *iseq = cfp->iseq;
-
-    if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
-	line_no = calc_line_no(cfp->iseq, cfp->pc);
-    }
-    return  (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]