Merge branch 'exc_mesg' of https://github.com/take-cheeze/mruby into take-cheeze...
authorYukihiro "Matz" Matsumoto <[email protected]>
Tue, 12 Oct 2021 13:14:11 +0000 (12 22:14 +0900)
committerYukihiro "Matz" Matsumoto <[email protected]>
Tue, 12 Oct 2021 13:14:11 +0000 (12 22:14 +0900)
1  2 
include/mruby/error.h
src/error.c
src/gc.c

@@@ -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
@@@ -5,33 -5,52 +5,54 @@@
  */
  
  #include <errno.h>
 -#include <stdarg.h>
  #include <stdlib.h>
 -#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 <mruby.h>
 +#include <mruby/array.h>
 +#include <mruby/irep.h>
 +#include <mruby/proc.h>
 +#include <mruby/string.h>
 +#include <mruby/variable.h>
 +#include <mruby/error.h>
 +#include <mruby/class.h>
 +#include <mruby/throw.h>
 +#include <mruby/presym.h>
  
 -mrb_value
 -mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
+ 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_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--;
    }
  }
  
diff --cc src/gc.c
Simple merge