summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backtrace.c36
-rw-r--r--src/class.c29
-rw-r--r--src/error.c4
-rw-r--r--src/vm.c4
4 files changed, 52 insertions, 21 deletions
diff --git a/src/backtrace.c b/src/backtrace.c
index a221d5e5c..6469fc069 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -12,6 +12,7 @@
#include "mruby/string.h"
#include "mruby/class.h"
#include "mruby/debug.h"
+#include "mruby/error.h"
typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...);
@@ -57,14 +58,12 @@ get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...
}
static void
-mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
+output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream)
{
mrb_callinfo *ci;
- mrb_int ciidx;
const char *filename, *method, *sep;
int i, lineno, tracehead = 1;
- ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx")));
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
ciidx = 10; /* ciidx is broken... */
@@ -87,7 +86,7 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
pc = mrb->c->cibase[i+1].pc - 1;
}
else {
- pc = (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc")));
+ pc = pc0;
}
filename = mrb_debug_get_filename(irep, pc - irep->iseq);
lineno = mrb_debug_get_line(irep, pc - irep->iseq);
@@ -129,6 +128,14 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
}
}
+static void
+exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
+{
+ output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))),
+ (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))),
+ func, stream);
+}
+
/* mrb_print_backtrace/mrb_get_backtrace:
function to retrieve backtrace information from the exception.
@@ -140,17 +147,32 @@ void
mrb_print_backtrace(mrb_state *mrb)
{
#ifdef ENABLE_STDIO
- mrb_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr);
+ exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr);
#endif
}
mrb_value
-mrb_get_backtrace(mrb_state *mrb, mrb_value self)
+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_value
+mrb_get_backtrace(mrb_state *mrb)
{
mrb_value ary;
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_code *pc = ci->pc;
+ mrb_int ciidx = ci - mrb->c->cibase - 1;
+ if (ciidx < 0) ciidx = 0;
ary = mrb_ary_new(mrb);
- mrb_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary));
+ output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary));
return ary;
}
diff --git a/src/class.c b/src/class.c
index ebe2bdb4a..84f8ea70e 100644
--- a/src/class.c
+++ b/src/class.c
@@ -731,8 +731,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
struct RClass *c;
c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
- c->super = super ? super : mrb->object_class;
- mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
+ if (super) {
+ c->super = super;
+ mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
+ }
+ else {
+ c->super = mrb->object_class;
+ }
c->mt = kh_init(mt, mrb);
return c;
}
@@ -1189,22 +1194,28 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
mrb_sym name;
mrb_value *a;
int alen;
- mrb_value inspect;
+ mrb_sym inspect;
+ mrb_value repr;
mrb_get_args(mrb, "n*", &name, &a, &alen);
- if (mrb_respond_to(mrb,mod,mrb_intern_lit(mrb, "inspect"))){
- inspect = mrb_funcall(mrb, mod, "inspect", 0);
- if (RSTRING_LEN(inspect) > 64) {
- inspect = mrb_any_to_s(mrb, mod);
+ inspect = mrb_intern_lit(mrb, "inspect");
+ if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
+ /* method missing in inspect; avoid recursion */
+ repr = mrb_any_to_s(mrb, mod);
+ }
+ else if (mrb_respond_to(mrb, mod, inspect)) {
+ repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0);
+ if (RSTRING_LEN(repr) > 64) {
+ repr = mrb_any_to_s(mrb, mod);
}
}
else {
- inspect = mrb_any_to_s(mrb, mod);
+ repr = mrb_any_to_s(mrb, mod);
}
mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), inspect);
+ mrb_sym2str(mrb, name), repr);
/* not reached */
return mrb_nil_value();
}
diff --git a/src/error.c b/src/error.c
index 8d0ec67e0..26dc97166 100644
--- a/src/error.c
+++ b/src/error.c
@@ -431,8 +431,6 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg)
}
}
-mrb_value mrb_get_backtrace(mrb_state*, mrb_value);
-
void
mrb_init_exception(mrb_state *mrb)
{
@@ -446,7 +444,7 @@ mrb_init_exception(mrb_state *mrb)
mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE());
mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE());
- mrb_define_method(mrb, e, "backtrace", mrb_get_backtrace, MRB_ARGS_NONE());
+ mrb_define_method(mrb, e, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
diff --git a/src/vm.c b/src/vm.c
index f11caedd7..13aa7c226 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1342,7 +1342,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int
goto L_RAISE;
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
- mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new(mrb, "double resume", 13));
+ mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new_lit(mrb, "double resume"));
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
@@ -2173,7 +2173,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int
mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
- return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
void