Index: EcnlProtoTool/trunk/mruby-1.3.0/src/backtrace.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/src/backtrace.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/src/backtrace.c	(revision 331)
@@ -5,97 +5,34 @@
 */
 
-#include "mruby.h"
-#include "mruby/variable.h"
-#include "mruby/proc.h"
-#include "mruby/array.h"
-#include "mruby/string.h"
-#include "mruby/class.h"
-#include "mruby/debug.h"
-#include "mruby/error.h"
-#include "mruby/numeric.h"
+#include <mruby.h>
+#include <mruby/variable.h>
+#include <mruby/proc.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+#include <mruby/debug.h>
+#include <mruby/error.h>
+#include <mruby/numeric.h>
+#include <mruby/data.h>
 
 struct backtrace_location {
-  int i;
   int lineno;
   const char *filename;
-  const char *method;
-  const char *sep;
-  const char *class_name;
+  mrb_sym method_id;
 };
 
-typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
-
-#ifndef MRB_DISABLE_STDIO
-
-struct print_backtrace_args {
-  FILE *stream;
-  int tracehead;
-};
-
-static void
-print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
-{
-  struct print_backtrace_args *args;
-
-  args = (struct print_backtrace_args*)data;
-
-  if (args->tracehead) {
-    fprintf(args->stream, "trace:\n");
-    args->tracehead = FALSE;
-  }
-
-  fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno);
-
-  if (loc->method) {
-    if (loc->class_name) {
-      fprintf(args->stream, ":in %s%s%s", loc->class_name, loc->sep, loc->method);
-    }
-    else {
-      fprintf(args->stream, ":in %s", loc->method);
-    }
-  }
-
-  fprintf(args->stream, "\n");
-}
-
-#endif
-
-static void
-get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
-{
-  mrb_value ary, str;
-  int ai;
-
-  ai = mrb_gc_arena_save(mrb);
-  ary = mrb_obj_value((struct RArray*)data);
-
-  str = mrb_str_new_cstr(mrb, loc->filename);
-  mrb_str_cat_lit(mrb, str, ":");
-  mrb_str_concat(mrb, str, mrb_fixnum_to_str(mrb, mrb_fixnum_value(loc->lineno), 10));
-
-  if (loc->method) {
-    mrb_str_cat_lit(mrb, str, ":in ");
-
-    if (loc->class_name) {
-      mrb_str_cat_cstr(mrb, str, loc->class_name);
-      mrb_str_cat_cstr(mrb, str, loc->sep);
-    }
-
-    mrb_str_cat_cstr(mrb, str, loc->method);
-  }
-
-  mrb_ary_push(mrb, ary, str);
-  mrb_gc_arena_restore(mrb, ai);
-}
-
-static void
-output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
-{
-  int i;
+typedef void (*each_backtrace_func)(mrb_state*, int i, struct backtrace_location*, void*);
+
+static const mrb_data_type bt_type = { "Backtrace", mrb_free };
+
+static void
+each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
+{
+  int i, j;
 
   if (ciidx >= mrb->c->ciend - mrb->c->cibase)
     ciidx = 10; /* ciidx is broken... */
 
-  for (i = ciidx; i >= 0; i--) {
+  for (i=ciidx, j=0; i >= 0; i--,j++) {
     struct backtrace_location loc;
     mrb_callinfo *ci;
@@ -109,4 +46,5 @@
 
     irep = ci->proc->body.irep;
+    if (!irep) continue;
 
     if (mrb->c->cibase[i].err) {
@@ -124,62 +62,87 @@
     if (loc.lineno == -1) continue;
 
-    if (ci->target_class == ci->proc->target_class) {
-      loc.sep = ".";
-    }
-    else {
-      loc.sep = "#";
-    }
-
     if (!loc.filename) {
       loc.filename = "(unknown)";
     }
 
-    loc.method = mrb_sym2name(mrb, ci->mid);
-    loc.class_name = mrb_class_name(mrb, ci->proc->target_class);
-    loc.i = i;
-    func(mrb, &loc, data);
-  }
-}
-
-static void
-exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
-{
-  mrb_value lastpc;
-  mrb_code *code;
-
-  lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"));
-  if (mrb_nil_p(lastpc)) {
-    code = NULL;
-  } else {
-    code = (mrb_code*)mrb_cptr(lastpc);
-  }
-
-  output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))),
-                   code, func, stream);
-}
-
-/* mrb_print_backtrace/mrb_get_backtrace:
-
-   function to retrieve backtrace information from the exception.
-   note that if you call method after the exception, call stack will be
-   overwritten.  So invoke these functions just after detecting exceptions.
+    loc.method_id = ci->mid;
+    func(mrb, j, &loc, data);
+  }
+}
+
+#ifndef MRB_DISABLE_STDIO
+
+static void
+print_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+  int i, n;
+  FILE *stream = stderr;
+
+  if (!mrb_array_p(backtrace)) return;
+  fprintf(stream, "trace:\n");
+
+  n = RARRAY_LEN(backtrace);
+  for (i=0; n--; i++) {
+    mrb_value entry = RARRAY_PTR(backtrace)[n];
+
+    if (mrb_string_p(entry)) {
+      fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+    }
+  }
+}
+
+static void
+print_packed_backtrace(mrb_state *mrb, mrb_value packed)
+{
+  FILE *stream = stderr;
+  struct backtrace_location *bt;
+  int n, i;
+
+  bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type);
+  if (bt == NULL) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace");
+  }
+  n = (mrb_int)RDATA(packed)->flags;
+
+  fprintf(stream, "trace:\n");
+  for (i = 0; n--; i++) {
+    int ai = mrb_gc_arena_save(mrb);
+    struct backtrace_location *entry = &bt[n];
+    if (entry->filename == NULL) continue;
+    fprintf(stream, "\t[%d] %s:%d", (int)i, entry->filename, entry->lineno);
+    if (entry->method_id != 0) {
+      const char *method_name;
+
+      method_name = mrb_sym2name(mrb, entry->method_id);
+      fprintf(stream, ":in %s", method_name);
+      mrb_gc_arena_restore(mrb, ai);
+    }
+    fprintf(stream, "\n");
+  }
+}
+
+/* mrb_print_backtrace
+
+   function to retrieve backtrace information from the last exception.
 */
-
-#ifndef MRB_DISABLE_STDIO
 
 MRB_API void
 mrb_print_backtrace(mrb_state *mrb)
 {
-  struct print_backtrace_args args;
-
-  if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
+  mrb_value backtrace;
+
+  if (!mrb->exc) {
     return;
   }
 
-  args.stream = stderr;
-  args.tracehead = TRUE;
-  exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
-}
-
+  backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+  if (mrb_nil_p(backtrace)) return;
+  if (mrb_array_p(backtrace)) {
+    print_backtrace(mrb, backtrace);
+  }
+  else {
+    print_packed_backtrace(mrb, backtrace);
+  }
+}
 #else
 
@@ -191,13 +154,90 @@
 #endif
 
+static void
+pack_backtrace_i(mrb_state *mrb,
+                 int i,
+                 struct backtrace_location *loc,
+                 void *data)
+{
+  struct backtrace_location *entry = (struct backtrace_location*)data;
+
+  entry[i] = *loc;
+}
+
+static mrb_value
+packed_backtrace(mrb_state *mrb)
+{
+  struct RData *backtrace;
+  ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase;
+  mrb_int len = (ciidx+1)*sizeof(struct backtrace_location);
+  void *ptr;
+
+  ptr = mrb_malloc(mrb, len);
+  memset(ptr, 0, len);
+  backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type);
+  backtrace->flags = (unsigned int)ciidx+1;
+  each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, ptr);
+  return mrb_obj_value(backtrace);
+}
+
+void
+mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
+{
+  mrb_value backtrace;
+  int ai = mrb_gc_arena_save(mrb);
+
+  backtrace = packed_backtrace(mrb);
+  mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
+  mrb_gc_arena_restore(mrb, ai);
+}
+
+mrb_value
+mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+  struct backtrace_location *bt;
+  mrb_int n, i;
+
+  if (mrb_nil_p(backtrace)) return mrb_ary_new_capa(mrb, 0);
+  if (mrb_array_p(backtrace)) return backtrace;
+  bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type);
+  if (bt == NULL) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace");
+  }
+  n = (mrb_int)RDATA(backtrace)->flags;
+  backtrace = mrb_ary_new_capa(mrb, n);
+  for (i = 0; i < n; i++) {
+    int ai = mrb_gc_arena_save(mrb);
+    struct backtrace_location *entry = &bt[i];
+    mrb_value btline;
+
+    if (entry->filename == NULL) continue;
+    btline = mrb_format(mrb, "%S:%S",
+                              mrb_str_new_cstr(mrb, entry->filename),
+                              mrb_fixnum_value(entry->lineno));
+    if (entry->method_id != 0) {
+      mrb_str_cat_lit(mrb, btline, ":in ");
+      mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id));
+    }
+    mrb_ary_push(mrb, backtrace, btline);
+    mrb_gc_arena_restore(mrb, ai);
+  }
+
+  return backtrace;
+}
+
 MRB_API mrb_value
-mrb_exc_backtrace(mrb_state *mrb, mrb_value self)
-{
-  mrb_value ary;
-
-  ary = mrb_ary_new(mrb);
-  exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary));
-
-  return ary;
+mrb_exc_backtrace(mrb_state *mrb, mrb_value exc)
+{
+  mrb_sym attr_name;
+  mrb_value backtrace;
+
+  attr_name = mrb_intern_lit(mrb, "backtrace");
+  backtrace = mrb_iv_get(mrb, exc, attr_name);
+  if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) {
+    return backtrace;
+  }
+  backtrace = mrb_unpack_backtrace(mrb, backtrace);
+  mrb_iv_set(mrb, exc, attr_name, backtrace);
+  return backtrace;
 }
 
@@ -205,13 +245,4 @@
 mrb_get_backtrace(mrb_state *mrb)
 {
-  mrb_value ary;
-  mrb_callinfo *ci = mrb->c->ci;
-  mrb_code *pc = ci->pc;
-  mrb_int ciidx = (mrb_int)(ci - mrb->c->cibase - 1);
-
-  if (ciidx < 0) ciidx = 0;
-  ary = mrb_ary_new(mrb);
-  output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary));
-
-  return ary;
-}
+  return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
+}
