From: Yukihiro "Matz" Matsumoto Date: Tue, 12 Oct 2021 13:14:11 +0000 (+0900) Subject: Merge branch 'exc_mesg' of https://github.com/take-cheeze/mruby into take-cheeze... X-Git-Tag: 3.1.0-rc~147^2 X-Git-Url: https://repo.or.cz/mruby.git/commitdiff_plain/291234c7aa17727d4a2e581330e0eb3c0f388c6b Merge branch 'exc_mesg' of https://github.com/take-cheeze/mruby into take-cheeze-exc_mesg --- 291234c7aa17727d4a2e581330e0eb3c0f388c6b diff --cc include/mruby/error.h index 20ca38586,ea12ef33e..80c21434f --- a/include/mruby/error.h +++ b/include/mruby/error.h @@@ -20,126 -18,23 +21,127 @@@ struct RException }; #define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v)) + #define MRB_EXC_MESG_STRING_FLAG 0x100 -void mrb_sys_fail(mrb_state *mrb, const char *mesg); -mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); -#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit)) -mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); -void mrb_exc_print(mrb_state *mrb, struct RObject *exc); -void mrb_print_backtrace(mrb_state *mrb); +MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg); +MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); +#define mrb_exc_new_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit)) +#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_lit(mrb, c, lit) +MRB_API mrb_value mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv); mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); mrb_value mrb_get_backtrace(mrb_state *mrb); -mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...); -/* declaration for fail method */ -mrb_value mrb_f_raise(mrb_state*, mrb_value); +MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...); + +/* declaration for `fail` method */ +MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); + +#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT32) || defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +struct RBreak { + MRB_OBJECT_HEADER; + const struct RProc *proc; + mrb_value val; +}; +#define mrb_break_value_get(brk) ((brk)->val) +#define mrb_break_value_set(brk, v) ((brk)->val = v) +#else +struct RBreak { + MRB_OBJECT_HEADER; + const struct RProc *proc; + union mrb_value_union value; +}; +#define RBREAK_VALUE_TT_MASK ((1 << 8) - 1) +static inline mrb_value +mrb_break_value_get(struct RBreak *brk) +{ + mrb_value val; + val.value = brk->value; + val.tt = (enum mrb_vtype)(brk->flags & RBREAK_VALUE_TT_MASK); + return val; +} +static inline void +mrb_break_value_set(struct RBreak *brk, mrb_value val) +{ + brk->value = val.value; + brk->flags &= ~RBREAK_VALUE_TT_MASK; + brk->flags |= val.tt; +} +#endif /* MRB_64BIT || MRB_USE_FLOAT32 || MRB_NAN_BOXING || MRB_WORD_BOXING */ +#define mrb_break_proc_get(brk) ((brk)->proc) +#define mrb_break_proc_set(brk, p) ((brk)->proc = p) + +#define RBREAK_TAG_FOREACH(f) \ + f(RBREAK_TAG_BREAK, 0) \ + f(RBREAK_TAG_BREAK_UPPER, 1) \ + f(RBREAK_TAG_BREAK_INTARGET, 2) \ + f(RBREAK_TAG_RETURN_BLOCK, 3) \ + f(RBREAK_TAG_RETURN, 4) \ + f(RBREAK_TAG_RETURN_TOPLEVEL, 5) \ + f(RBREAK_TAG_JUMP, 6) \ + f(RBREAK_TAG_STOP, 7) + +#define RBREAK_TAG_DEFINE(tag, i) tag = i, +enum { + RBREAK_TAG_FOREACH(RBREAK_TAG_DEFINE) +}; +#undef RBREAK_TAG_DEFINE + +#define RBREAK_TAG_BIT 3 +#define RBREAK_TAG_BIT_OFF 8 +#define RBREAK_TAG_MASK (~(~UINT32_C(0) << RBREAK_TAG_BIT)) + +static inline uint32_t +mrb_break_tag_get(struct RBreak *brk) +{ + return (brk->flags >> RBREAK_TAG_BIT_OFF) & RBREAK_TAG_MASK; +} + +static inline void +mrb_break_tag_set(struct RBreak *brk, uint32_t tag) +{ + brk->flags &= ~(RBREAK_TAG_MASK << RBREAK_TAG_BIT_OFF); + brk->flags |= (tag & RBREAK_TAG_MASK) << RBREAK_TAG_BIT_OFF; +} + +/** + * Protect + * + */ +typedef mrb_value mrb_protect_error_func(mrb_state *mrb, void *userdata); +MRB_API mrb_value mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, mrb_bool *error); + +/** + * Protect (takes mrb_value for body argument) + * + * Implemented in the mruby-error mrbgem + */ +MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state); + +/** + * Ensure + * + * Implemented in the mruby-error mrbgem + */ +MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t ensure, mrb_value e_data); + +/** + * Rescue + * + * Implemented in the mruby-error mrbgem + */ +MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data); + +/** + * Rescue exception + * + * Implemented in the mruby-error mrbgem + */ +MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes); -#if defined(__cplusplus) -} /* extern "C" { */ -#endif +MRB_END_DECL #endif /* MRUBY_ERROR_H */ diff --cc src/error.c index 5ceff2436,2f893a382..b2ae38295 --- a/src/error.c +++ b/src/error.c @@@ -5,33 -5,52 +5,54 @@@ */ #include -#include #include -#include "mruby.h" -#include "mruby/array.h" -#include "mruby/irep.h" -#include "mruby/proc.h" -#include "mruby/string.h" -#include "mruby/variable.h" -#include "mruby/debug.h" -#include "mruby/error.h" -#include "mruby/class.h" -#include "mrb_throw.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + static void + exc_mesg_set(mrb_state *mrb, struct RException *exc, mrb_value mesg) + { + if (mrb_string_p(mesg)) { + exc->flags |= MRB_EXC_MESG_STRING_FLAG; + exc->mesg = RSTRING(mesg); + mrb_field_write_barrier_value(mrb, (struct RBasic*)exc, mesg); + } + else if (!mrb_nil_p(mesg)) { + exc->flags &= ~MRB_EXC_MESG_STRING_FLAG; + mrb_obj_iv_set(mrb, (struct RObject*)exc, mrb_intern_lit(mrb, "mesg"), mesg); + } + } + + static mrb_value + exc_mesg_get(mrb_state *mrb, struct RException *exc) + { + return (exc->flags & MRB_EXC_MESG_STRING_FLAG) != 0 + ? mrb_obj_value(exc->mesg) : mrb_obj_iv_get(mrb, (struct RObject*)exc, mrb_intern_lit(mrb, "mesg")); + } + -mrb_value -mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len) +MRB_API mrb_value +mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { - mrb_value arg = mrb_str_new(mrb, ptr, len); - return mrb_obj_new(mrb, c, 1, &arg); + mrb_ensure_string_type(mrb, str); + + struct RBasic* e = mrb_obj_alloc(mrb, MRB_TT_EXCEPTION, c); + mrb_value exc = mrb_obj_value(e); + mrb_iv_set(mrb, exc, MRB_SYM(mesg), str); + return exc; } -mrb_value -mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) +MRB_API mrb_value +mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) { - str = mrb_str_to_str(mrb, str); - return mrb_obj_new(mrb, c, 1, &str); + return mrb_exc_new_str(mrb, c, mrb_str_new(mrb, ptr, len)); } /* @@@ -130,60 -151,75 +151,60 @@@ exc_message(mrb_state *mrb, mrb_value e * returns message and class name. */ -static mrb_value -exc_inspect(mrb_state *mrb, mrb_value exc) +mrb_value +mrb_exc_inspect(mrb_state *mrb, mrb_value exc) { - mrb_value mesg = mrb_attr_get(mrb, exc, MRB_SYM(mesg)); - mrb_value str, mesg, file, line; - mrb_bool append_mesg; - - mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc)); - file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file")); - line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line")); ++ mrb_value mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc)); + mrb_value cname = mrb_mod_to_s(mrb, mrb_obj_value(mrb_obj_class(mrb, exc))); + mesg = mrb_obj_as_string(mrb, mesg); + return RSTRING_LEN(mesg) == 0 ? cname : mrb_format(mrb, "%v (%v)", mesg, cname); +} - append_mesg = !mrb_nil_p(mesg); - if (append_mesg) { - mesg = mrb_obj_as_string(mrb, mesg); - append_mesg = RSTRING_LEN(mesg) > 0; - } +void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc); - if (!mrb_nil_p(file) && !mrb_nil_p(line)) { - str = mrb_str_dup(mrb, file); - mrb_str_cat_lit(mrb, str, ":"); - mrb_str_append(mrb, str, line); - mrb_str_cat_lit(mrb, str, ": "); - if (append_mesg) { - mrb_str_append(mrb, str, mesg); - mrb_str_cat_lit(mrb, str, " ("); - } - mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); - if (append_mesg) { - mrb_str_cat_lit(mrb, str, ")"); - } +static void +set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace) +{ + if (!mrb_array_p(backtrace)) { + type_err: + mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String"); } else { - const char *cname = mrb_obj_classname(mrb, exc); - str = mrb_str_new_cstr(mrb, cname); - mrb_str_cat_lit(mrb, str, ": "); - if (append_mesg) { - mrb_str_append(mrb, str, mesg); - } - else { - mrb_str_cat_cstr(mrb, str, cname); + const mrb_value *p = RARRAY_PTR(backtrace); + const mrb_value *pend = p + RARRAY_LEN(backtrace); + + while (p < pend) { + if (!mrb_string_p(*p)) goto type_err; + p++; } } - return str; + mrb_iv_set(mrb, exc, MRB_SYM(backtrace), backtrace); } - -static void -exc_debug_info(mrb_state *mrb, struct RObject *exc) +static mrb_value +exc_set_backtrace(mrb_state *mrb, mrb_value exc) { - mrb_callinfo *ci = mrb->c->ci; - mrb_code *pc = ci->pc; + mrb_value backtrace = mrb_get_arg1(mrb); - mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase))); - while (ci >= mrb->c->cibase) { - mrb_code *err = ci->err; - - if (!err && pc) err = pc - 1; - if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { - mrb_irep *irep = ci->proc->body.irep; + set_backtrace(mrb, exc, backtrace); + return backtrace; +} - int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq)); - char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq)); - if (line != -1 && file) { - mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); - mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); - return; - } +void +mrb_exc_set(mrb_state *mrb, mrb_value exc) +{ + if (mrb_nil_p(exc)) { + mrb->exc = 0; + } + else { + mrb->exc = mrb_obj_ptr(exc); + if (mrb->gc.arena_idx > 0 && + (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) { + mrb->gc.arena_idx--; + } + if (!mrb->gc.out_of_memory && !mrb_frozen_p(mrb->exc)) { + mrb_keep_backtrace(mrb, exc); } - pc = ci->pc; - ci--; } }