diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/backtrace.c | 36 | ||||
| -rw-r--r-- | src/class.c | 29 | ||||
| -rw-r--r-- | src/error.c | 4 | ||||
| -rw-r--r-- | src/vm.c | 4 |
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 */ @@ -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 |
