diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2015-12-29 23:49:33 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2015-12-29 23:49:33 +0900 |
| commit | ee3fa1be49e4d48acd7fdd6bd049a8d5d4d4724c (patch) | |
| tree | 49015de74ab4953c278e59dd9299858d46979f10 /src/error.c | |
| parent | e132de9e8eaf095f6f8b826e34a1c145403c3311 (diff) | |
| parent | 0ebac02813d6506f92c9aaceaa00c6f902a56a03 (diff) | |
| download | mruby-ee3fa1be49e4d48acd7fdd6bd049a8d5d4d4724c.tar.gz mruby-ee3fa1be49e4d48acd7fdd6bd049a8d5d4d4724c.zip | |
Merge pull request #3065 from kou/support-backtrace-after-method-calls
Support backtrace after method calls
Diffstat (limited to 'src/error.c')
| -rw-r--r-- | src/error.c | 87 |
1 files changed, 79 insertions, 8 deletions
diff --git a/src/error.c b/src/error.c index 15a969d93..14e4ab4d3 100644 --- a/src/error.c +++ b/src/error.c @@ -174,6 +174,42 @@ exc_inspect(mrb_state *mrb, mrb_value exc) return str; } +void mrb_save_backtrace(mrb_state *mrb); +mrb_value mrb_restore_backtrace(mrb_state *mrb); + +static mrb_value +exc_get_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)) { + if (mrb_obj_ptr(exc) == mrb->backtrace.exc && mrb->backtrace.n > 0) { + backtrace = mrb_restore_backtrace(mrb); + mrb->backtrace.n = 0; + mrb->backtrace.exc = 0; + } + else { + backtrace = mrb_exc_backtrace(mrb, exc); + } + mrb_iv_set(mrb, exc, attr_name, backtrace); + } + + return backtrace; +} + +static mrb_value +exc_set_backtrace(mrb_state *mrb, mrb_value exc) +{ + mrb_value backtrace; + + mrb_get_args(mrb, "o", &backtrace); + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); + + return backtrace; +} static void exc_debug_info(mrb_state *mrb, struct RObject *exc) @@ -202,12 +238,52 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) } } +static void +set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) +{ + mrb_funcall(mrb, info, "set_backtrace", 1, bt); +} + +static mrb_bool +have_backtrace(mrb_state *mrb, struct RObject *exc) +{ + return !mrb_nil_p(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "backtrace"))); +} + +void +mrb_exc_set(mrb_state *mrb, mrb_value exc) +{ + if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) { + mrb_value target_exc = mrb_nil_value(); + if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) { + target_exc = mrb_obj_value(mrb->exc); + } + else if (!mrb_nil_p(exc) && mrb_obj_ptr(exc) == mrb->backtrace.exc) { + target_exc = exc; + } + if (!mrb_nil_p(target_exc)) { + mrb_value backtrace; + backtrace = mrb_restore_backtrace(mrb); + set_backtrace(mrb, target_exc, backtrace); + } + } + + mrb->backtrace.n = 0; + if (mrb_nil_p(exc)) { + mrb->exc = 0; + } + else { + mrb->exc = mrb_obj_ptr(exc); + } +} + MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { - mrb->exc = mrb_obj_ptr(exc); + mrb_exc_set(mrb, exc); if (!mrb->gc.out_of_memory) { exc_debug_info(mrb, mrb->exc); + mrb_save_backtrace(mrb); } if (!mrb->jmp) { mrb_p(mrb, exc); @@ -337,12 +413,6 @@ mrb_bug(mrb_state *mrb, const char *fmt, ...) exit(EXIT_FAILURE); } -static void -set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) -{ - mrb_funcall(mrb, info, "set_backtrace", 1, bt); -} - static mrb_value make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr) { @@ -449,7 +519,8 @@ mrb_init_exception(mrb_state *mrb) mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); - mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "backtrace", exc_get_backtrace, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1)); mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ |
