summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby.h26
-rw-r--r--include/mruby/compile.h2
-rw-r--r--include/mruby/hash.h10
-rw-r--r--include/mruby/proc.h2
-rw-r--r--include/mruby/throw.h12
-rw-r--r--include/mruby/value.h11
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c4
-rw-r--r--mrbgems/mruby-compiler/core/parse.y2
-rw-r--r--mrbgems/mruby-eval/src/eval.c8
-rw-r--r--mrbgems/mruby-fiber/src/fiber.c75
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c44
-rw-r--r--src/backtrace.c223
-rw-r--r--src/error.c87
-rw-r--r--src/gc.c26
-rw-r--r--src/hash.c6
-rw-r--r--src/load.c8
-rw-r--r--src/state.c3
-rw-r--r--src/string.c19
-rw-r--r--src/symbol.c4
-rw-r--r--src/vm.c108
-rw-r--r--test/assert.rb6
-rw-r--r--test/t/exception.rb47
22 files changed, 582 insertions, 151 deletions
diff --git a/include/mruby.h b/include/mruby.h
index 1ea0156e8..9a3b72c74 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -87,7 +87,7 @@ typedef struct {
enum mrb_fiber_state {
MRB_FIBER_CREATED = 0,
MRB_FIBER_RUNNING,
- MRB_FIBER_RESUMING,
+ MRB_FIBER_RESUMED,
MRB_FIBER_SUSPENDED,
MRB_FIBER_TRANSFERRED,
MRB_FIBER_TERMINATED,
@@ -108,11 +108,20 @@ struct mrb_context {
int esize;
enum mrb_fiber_state status;
+ mrb_bool vmexec;
struct RFiber *fib;
};
struct mrb_jmpbuf;
+typedef struct {
+ const char *filename;
+ int lineno;
+ struct RClass *klass;
+ const char *sep;
+ mrb_sym method_id;
+} mrb_backtrace_entry;
+
typedef void (*mrb_atexit_func)(struct mrb_state*);
typedef struct mrb_state {
@@ -125,6 +134,12 @@ typedef struct mrb_state {
struct mrb_context *root_c;
struct RObject *exc; /* exception */
+ struct {
+ struct RObject *exc;
+ int n;
+ int n_allocated;
+ mrb_backtrace_entry *entries;
+ } backtrace;
struct iv_tbl *globals; /* global variable table */
struct RObject *top_self;
@@ -918,8 +933,13 @@ MRB_API void* mrb_default_allocf(mrb_state*, void*, size_t, void*);
MRB_API mrb_value mrb_top_self(mrb_state *);
MRB_API mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value);
-MRB_API mrb_value mrb_toplevel_run(mrb_state*, struct RProc*);
-MRB_API mrb_value mrb_context_run(mrb_state*, struct RProc*, mrb_value, unsigned int);
+MRB_API mrb_value mrb_top_run(mrb_state*, struct RProc*, mrb_value, unsigned int);
+MRB_API mrb_value mrb_vm_run(mrb_state*, struct RProc*, mrb_value, unsigned int);
+MRB_API mrb_value mrb_vm_exec(mrb_state*, struct RProc*, mrb_code*);
+/* compatibility macros */
+#define mrb_toplevel_run_keep(m,p,k) mrb_top_run((m),(p),mrb_top_self(m),(k))
+#define mrb_toplevel_run(m,p) mrb_toplevel_run_keep((m),(p),0)
+#define mrb_context_run(m,p,s,k) mrb_vm_run((m),(p),(s),(k))
MRB_API void mrb_p(mrb_state*, mrb_value);
MRB_API mrb_int mrb_obj_id(mrb_value obj);
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index 8b813b1c1..633eb1b74 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -40,8 +40,6 @@ MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
MRB_API const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
-MRB_API mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int);
-
/* AST node structure */
typedef struct mrb_ast_node {
struct mrb_ast_node *car, *cdr;
diff --git a/include/mruby/hash.h b/include/mruby/hash.h
index 1d00a33ab..21366c459 100644
--- a/include/mruby/hash.h
+++ b/include/mruby/hash.h
@@ -8,6 +8,7 @@
#define MRUBY_HASH_H
#include "common.h"
+#include <mruby/khash.h>
/**
* Hash class
@@ -59,6 +60,15 @@ MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
*/
MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
+/* declaration of struct kh_ht */
+/* be careful when you touch the internal */
+typedef struct {
+ mrb_value v;
+ mrb_int n;
+} mrb_hash_value;
+
+KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
+
/* RHASH_TBL allocates st_table if not available. */
#define RHASH(obj) ((struct RHash*)(mrb_ptr(obj)))
#define RHASH_TBL(h) (RHASH(h)->ht)
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 24f0f319f..5965a2b39 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -27,6 +27,8 @@ struct REnv {
#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1)
#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0)
+MRB_API void mrb_env_unshare(mrb_state*, struct REnv*);
+
struct RProc {
MRB_OBJECT_HEADER;
union {
diff --git a/include/mruby/throw.h b/include/mruby/throw.h
index 7f720d512..e4b0f1f2b 100644
--- a/include/mruby/throw.h
+++ b/include/mruby/throw.h
@@ -20,11 +20,19 @@ typedef mrb_int mrb_jmpbuf_impl;
#include <setjmp.h>
-#define MRB_TRY(buf) do { if (setjmp((buf)->impl) == 0) {
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#define MRB_SETJMP _setjmp
+#define MRB_LONGJMP _longjmp
+#else
+#define MRB_SETJMP setjmp
+#define MRB_LONGJMP longjmp
+#endif
+
+#define MRB_TRY(buf) do { if (MRB_SETJMP((buf)->impl) == 0) {
#define MRB_CATCH(buf) } else {
#define MRB_END_EXC(buf) } } while(0)
-#define MRB_THROW(buf) longjmp((buf)->impl, 1);
+#define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1);
#define mrb_jmpbuf_impl jmp_buf
#endif
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 04e5644d2..0eac19df9 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -22,21 +22,32 @@ struct mrb_state;
# error "You can't define MRB_INT16 and MRB_INT64 at the same time."
#endif
+#include <inttypes.h>
+
#if defined(MRB_INT64)
typedef int64_t mrb_int;
# define MRB_INT_BIT 64
# define MRB_INT_MIN (INT64_MIN>>MRB_FIXNUM_SHIFT)
# define MRB_INT_MAX (INT64_MAX>>MRB_FIXNUM_SHIFT)
+# define MRB_PRIo PRIo64
+# define MRB_PRId PRId64
+# define MRB_PRIx PRIx64
#elif defined(MRB_INT16)
typedef int16_t mrb_int;
# define MRB_INT_BIT 16
# define MRB_INT_MIN (INT16_MIN>>MRB_FIXNUM_SHIFT)
# define MRB_INT_MAX (INT16_MAX>>MRB_FIXNUM_SHIFT)
+# define MRB_PRIo PRIo16
+# define MRB_PRId PRId16
+# define MRB_PRIx PRIx16
#else
typedef int32_t mrb_int;
# define MRB_INT_BIT 32
# define MRB_INT_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT)
# define MRB_INT_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT)
+# define MRB_PRIo PRIo32
+# define MRB_PRId PRId32
+# define MRB_PRIx PRIx32
#endif
#ifdef MRB_USE_FLOAT
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index bdba2d2eb..55bbc513b 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -359,7 +359,7 @@ ctrl_c_handler(int signo)
int
main(int argc, char **argv)
{
- char ruby_code[1024] = { 0 };
+ char ruby_code[4096] = { 0 };
char last_code_line[1024] = { 0 };
#ifndef ENABLE_READLINE
int last_char;
@@ -546,7 +546,7 @@ done:
}
/* pass a proc for evaulation */
/* evaluate the bytecode */
- result = mrb_context_run(mrb,
+ result = mrb_vm_run(mrb,
proc,
mrb_top_self(mrb),
stack_keep);
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index b08775cc7..301d1bf65 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -5634,7 +5634,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
if (mrb->c->ci) {
mrb->c->ci->target_class = target;
}
- v = mrb_toplevel_run_keep(mrb, proc, keep);
+ v = mrb_top_run(mrb, proc, mrb_top_self(mrb), keep);
if (mrb->exc) return mrb_nil_value();
return v;
}
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index eef1f5046..7c5b08d1a 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -130,6 +130,8 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
}
}
+void mrb_codedump_all(mrb_state*, struct RProc*);
+
static struct RProc*
create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, char *file, mrb_int line)
{
@@ -209,7 +211,7 @@ f_eval(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
proc = create_proc_from_string(mrb, s, len, binding, file, line);
- ret = mrb_toplevel_run(mrb, proc);
+ ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
if (mrb->exc) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
}
@@ -236,12 +238,14 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
char *file = NULL;
mrb_int line = 1;
mrb_value cv;
+ struct RProc *proc;
mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
c->ci->acc = CI_ACC_SKIP;
cv = mrb_singleton_class(mrb, self);
c->ci->target_class = mrb_class_ptr(cv);
- return mrb_run(mrb, create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line), self);
+ proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
+ return mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
}
else {
mrb_get_args(mrb, "&", &b);
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c
index c140b6eac..232c925d3 100644
--- a/mrbgems/mruby-fiber/src/fiber.c
+++ b/mrbgems/mruby-fiber/src/fiber.c
@@ -7,6 +7,7 @@
#define FIBER_STACK_INIT_SIZE 64
#define FIBER_CI_INIT_SIZE 8
+#define CI_ACC_RESUMED -3
/*
* call-seq:
@@ -155,10 +156,9 @@ fiber_result(mrb_state *mrb, const mrb_value *a, mrb_int len)
/* mark return from context modifying method */
#define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL
-static mrb_value
-fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume)
+static void
+fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c)
{
- struct mrb_context *c = fiber_check(mrb, self);
mrb_callinfo *ci;
for (ci = c->ci; ci >= c->cibase; ci--) {
@@ -166,16 +166,26 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary");
}
}
+}
+
+static mrb_value
+fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec)
+{
+ struct mrb_context *c = fiber_check(mrb, self);
+ struct mrb_context *old_c = mrb->c;
+ mrb_value value;
+
+ fiber_check_cfunc(mrb, c);
if (resume && c->status == MRB_FIBER_TRANSFERRED) {
mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
}
- if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) {
- mrb_raise(mrb, E_FIBER_ERROR, "double resume");
+ if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) {
+ mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)");
}
if (c->status == MRB_FIBER_TERMINATED) {
mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
}
- mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED;
+ mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
if (c->status == MRB_FIBER_CREATED) {
mrb_value *b = c->stack+1;
@@ -185,22 +195,24 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
*b++ = *a++;
}
c->cibase->argc = len;
- if (c->prev->fib)
- mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
- c->status = MRB_FIBER_RUNNING;
- mrb->c = c;
-
- MARK_CONTEXT_MODIFY(c);
- return c->ci->proc->env->stack[0];
+ value = c->stack[0] = c->ci->proc->env->stack[0];
+ }
+ else {
+ value = fiber_result(mrb, a, len);
}
- MARK_CONTEXT_MODIFY(c);
- if (c->prev->fib)
- mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
mrb_write_barrier(mrb, (struct RBasic*)c->fib);
c->status = MRB_FIBER_RUNNING;
mrb->c = c;
- return fiber_result(mrb, a, len);
+
+ if (vmexec) {
+ c->vmexec = TRUE;
+ value = mrb_vm_exec(mrb, c->ci[-1].proc, c->ci->pc);
+ mrb->c = old_c;
+ }
+ else {
+ MARK_CONTEXT_MODIFY(c);
+ }
+ return value;
}
/*
@@ -223,16 +235,20 @@ fiber_resume(mrb_state *mrb, mrb_value self)
{
mrb_value *a;
mrb_int len;
+ mrb_bool vmexec = FALSE;
mrb_get_args(mrb, "*", &a, &len);
- return fiber_switch(mrb, self, len, a, TRUE);
+ if (mrb->c->ci->acc < 0) {
+ vmexec = TRUE;
+ }
+ return fiber_switch(mrb, self, len, a, TRUE, vmexec);
}
/* resume thread with given arguments */
MRB_API mrb_value
mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a)
{
- return fiber_switch(mrb, fib, len, a, TRUE);
+ return fiber_switch(mrb, fib, len, a, TRUE, TRUE);
}
/*
@@ -280,6 +296,7 @@ fiber_transfer(mrb_state *mrb, mrb_value self)
mrb_value* a;
mrb_int len;
+ fiber_check_cfunc(mrb, mrb->c);
mrb_get_args(mrb, "*", &a, &len);
if (c == mrb->root_c) {
@@ -295,7 +312,7 @@ fiber_transfer(mrb_state *mrb, mrb_value self)
return fiber_result(mrb, a, len);
}
- return fiber_switch(mrb, self, len, a, FALSE);
+ return fiber_switch(mrb, self, len, a, FALSE, FALSE);
}
/* yield values to the caller fiber */
@@ -304,13 +321,7 @@ MRB_API mrb_value
mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
{
struct mrb_context *c = mrb->c;
- mrb_callinfo *ci;
- for (ci = c->ci; ci >= c->cibase; ci--) {
- if (ci->acc < 0) {
- mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary");
- }
- }
if (!c->prev) {
mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber");
}
@@ -319,8 +330,12 @@ mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
c->status = MRB_FIBER_SUSPENDED;
mrb->c = c->prev;
c->prev = NULL;
- MARK_CONTEXT_MODIFY(mrb->c);
+ if (c->vmexec) {
+ c->vmexec = FALSE;
+ mrb->c->ci->acc = CI_ACC_RESUMED;
+ }
mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ MARK_CONTEXT_MODIFY(mrb->c);
return fiber_result(mrb, a, len);
}
@@ -332,7 +347,9 @@ mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
* along any arguments that were passed to it. The fiber will resume
* processing at this point when <code>resume</code> is called next.
* Any arguments passed to the next <code>resume</code> will be the
- * value that this <code>Fiber.yield</code> expression evaluates to.
+ *
+ * mruby limitation: Fiber resume/yield cannot cross C function boundary.
+ * thus you cannot yield from #initialize which is called by mrb_funcall().
*/
static mrb_value
fiber_yield(mrb_state *mrb, mrb_value self)
diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c
index 33e0931f9..f8ca217ac 100644
--- a/mrbgems/mruby-sprintf/src/sprintf.c
+++ b/mrbgems/mruby-sprintf/src/sprintf.c
@@ -759,7 +759,7 @@ retry:
case 'B':
case 'u': {
mrb_value val = GETARG();
- char fbuf[32], nbuf[68], *s;
+ char nbuf[68], *s;
const char *prefix = NULL;
int sign = 0, dots = 0;
char sc = 0;
@@ -836,8 +836,6 @@ retry:
}
}
if (sign) {
- char c = *p;
- if (c == 'i') c = 'd'; /* %d and %i are identical */
if (v < 0) {
v = -v;
sc = '-';
@@ -851,28 +849,40 @@ retry:
sc = ' ';
width--;
}
- if (base == 2) {
- snprintf(nbuf, sizeof(nbuf), "%s", RSTRING_PTR(val));
- }
- else {
- snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
- snprintf(nbuf, sizeof(nbuf), fbuf, v);
+ switch (base) {
+ case 2:
+ strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf));
+ break;
+ case 8:
+ snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIo, v);
+ break;
+ case 10:
+ snprintf(nbuf, sizeof(nbuf), "%"MRB_PRId, v);
+ break;
+ case 16:
+ snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIx, v);
+ break;
}
s = nbuf;
}
else {
- char c = *p;
- if (c == 'X') c = 'x';
s = nbuf;
if (v < 0) {
dots = 1;
}
- if (base == 2) {
- snprintf(++s, sizeof(nbuf) - 1, "%s", RSTRING_PTR(val));
- }
- else {
- snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
- snprintf(++s, sizeof(nbuf) - 1, fbuf, v);
+ switch (base) {
+ case 2:
+ strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1);
+ break;
+ case 8:
+ snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIo, v);
+ break;
+ case 10:
+ snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRId, v);
+ break;
+ case 16:
+ snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIx, v);
+ break;
}
if (v < 0) {
char d;
diff --git a/src/backtrace.c b/src/backtrace.c
index 80a5e2935..2fce6645d 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -14,6 +14,15 @@
#include <mruby/error.h>
#include <mruby/numeric.h>
+struct backtrace_location_raw {
+ int i;
+ int lineno;
+ const char *filename;
+ mrb_sym method_id;
+ const char *sep;
+ struct RClass *klass;
+};
+
struct backtrace_location {
int i;
int lineno;
@@ -23,6 +32,7 @@ struct backtrace_location {
const char *class_name;
};
+typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location_raw*, void*);
typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
#ifndef MRB_DISABLE_STDIO
@@ -89,7 +99,7 @@ get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
}
static void
-output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
+each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
{
int i;
@@ -97,7 +107,7 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
ciidx = 10; /* ciidx is broken... */
for (i = ciidx; i >= 0; i--) {
- struct backtrace_location loc;
+ struct backtrace_location_raw loc;
mrb_callinfo *ci;
mrb_irep *irep;
mrb_code *pc;
@@ -134,13 +144,43 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
loc.filename = "(unknown)";
}
- loc.method = mrb_sym2name(mrb, ci->mid);
- loc.class_name = mrb_class_name(mrb, ci->proc->target_class);
+ loc.method_id = ci->mid;
+ loc.klass = ci->proc->target_class;
loc.i = i;
func(mrb, &loc, data);
}
}
+struct output_backtrace_args {
+ output_stream_func func;
+ void *data;
+};
+
+static void
+output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data)
+{
+ struct backtrace_location loc;
+ struct output_backtrace_args *args = data;
+
+ loc.i = loc_raw->i;
+ loc.lineno = loc_raw->lineno;
+ loc.filename = loc_raw->filename;
+ loc.method = mrb_sym2name(mrb, loc_raw->method_id);
+ loc.sep = loc_raw->sep;
+ loc.class_name = mrb_class_name(mrb, loc_raw->klass);
+
+ args->func(mrb, &loc, args->data);
+}
+
+static void
+output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
+{
+ struct output_backtrace_args args;
+ args.func = func;
+ args.data = data;
+ each_backtrace(mrb, ciidx, pc0, output_backtrace_i, &args);
+}
+
static void
exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream)
{
@@ -167,18 +207,76 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
#ifndef MRB_DISABLE_STDIO
+static void
+print_backtrace(mrb_state *mrb, mrb_value backtrace)
+{
+ int i, n;
+ FILE *stream = stderr;
+
+ fprintf(stream, "trace:\n");
+
+ n = RARRAY_LEN(backtrace);
+ for (i = 0; i < n; i++) {
+ mrb_value entry = RARRAY_PTR(backtrace)[i];
+
+ fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry));
+ }
+}
+
+static void
+print_backtrace_saved(mrb_state *mrb)
+{
+ int i;
+ FILE *stream = stderr;
+
+ fprintf(stream, "trace:\n");
+ for (i = 0; i < mrb->backtrace.n; i++) {
+ mrb_backtrace_entry *entry;
+
+ entry = &(mrb->backtrace.entries[i]);
+ fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno);
+
+ if (entry->method_id != 0) {
+ const char *method_name;
+
+ method_name = mrb_sym2name(mrb, entry->method_id);
+ if (entry->klass) {
+ fprintf(stream, ":in %s%s%s",
+ mrb_class_name(mrb, entry->klass),
+ entry->sep,
+ method_name);
+ }
+ else {
+ fprintf(stream, ":in %s", method_name);
+ }
+ }
+
+ fprintf(stream, "\n");
+ }
+}
+
MRB_API void
mrb_print_backtrace(mrb_state *mrb)
{
- struct print_backtrace_args args;
+ mrb_value backtrace;
if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {
return;
}
- args.stream = stderr;
- args.tracehead = TRUE;
- exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
+ backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+ if (!mrb_nil_p(backtrace)) {
+ print_backtrace(mrb, backtrace);
+ }
+ else if (mrb->backtrace.n > 0) {
+ print_backtrace_saved(mrb);
+ }
+ else {
+ struct print_backtrace_args args;
+ args.stream = stderr;
+ args.tracehead = TRUE;
+ exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
+ }
}
#else
@@ -215,3 +313,112 @@ mrb_get_backtrace(mrb_state *mrb)
return ary;
}
+
+void
+mrb_free_backtrace(mrb_state *mrb)
+{
+ mrb->backtrace.exc = 0;
+ mrb->backtrace.n = 0;
+ mrb->backtrace.n_allocated = 0;
+ mrb_free(mrb, mrb->backtrace.entries);
+}
+
+static void
+save_backtrace_i(mrb_state *mrb,
+ struct backtrace_location_raw *loc_raw,
+ void *data)
+{
+ mrb_backtrace_entry *entry;
+
+ if (loc_raw->i >= mrb->backtrace.n_allocated) {
+ int new_n_allocated;
+ if (mrb->backtrace.n_allocated == 0) {
+ new_n_allocated = 8;
+ }
+ else {
+ new_n_allocated = mrb->backtrace.n_allocated * 2;
+ }
+ mrb->backtrace.entries =
+ mrb_realloc(mrb,
+ mrb->backtrace.entries,
+ sizeof(mrb_backtrace_entry) * new_n_allocated);
+ mrb->backtrace.n_allocated = new_n_allocated;
+ }
+
+ entry = &mrb->backtrace.entries[mrb->backtrace.n];
+ entry->filename = loc_raw->filename;
+ entry->lineno = loc_raw->lineno;
+ entry->klass = loc_raw->klass;
+ entry->sep = loc_raw->sep;
+ entry->method_id = loc_raw->method_id;
+
+ mrb->backtrace.n++;
+}
+
+void
+mrb_save_backtrace(mrb_state *mrb)
+{
+ mrb_value lastpc;
+ mrb_code *code;
+ mrb_int ciidx;
+
+ mrb->backtrace.n = 0;
+ mrb->backtrace.exc = 0;
+
+ if (!mrb->exc)
+ return;
+
+ mrb->backtrace.exc = mrb->exc;
+
+ lastpc = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"));
+ if (mrb_nil_p(lastpc)) {
+ code = NULL;
+ }
+ else {
+ code = (mrb_code*)mrb_cptr(lastpc);
+ }
+
+ ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx")));
+
+ each_backtrace(mrb, ciidx, code, save_backtrace_i, NULL);
+}
+
+mrb_value
+mrb_restore_backtrace(mrb_state *mrb)
+{
+ int i;
+ mrb_value backtrace;
+
+ backtrace = mrb_ary_new(mrb);
+ for (i = 0; i < mrb->backtrace.n; i++) {
+ int ai;
+ mrb_backtrace_entry *entry;
+ mrb_value mrb_entry;
+
+ ai = mrb_gc_arena_save(mrb);
+ entry = &(mrb->backtrace.entries[i]);
+
+ mrb_entry = mrb_str_new_cstr(mrb, entry->filename);
+ mrb_str_cat_lit(mrb, mrb_entry, ":");
+ mrb_str_concat(mrb, mrb_entry,
+ mrb_fixnum_to_str(mrb,
+ mrb_fixnum_value(entry->lineno),
+ 10));
+ if (entry->method_id != 0) {
+ mrb_str_cat_lit(mrb, mrb_entry, ":in ");
+
+ if (entry->klass) {
+ mrb_str_cat_cstr(mrb, mrb_entry, mrb_class_name(mrb, entry->klass));
+ mrb_str_cat_cstr(mrb, mrb_entry, entry->sep);
+ }
+
+ mrb_str_cat_cstr(mrb, mrb_entry, mrb_sym2name(mrb, entry->method_id));
+ }
+
+ mrb_ary_push(mrb, backtrace, mrb_entry);
+
+ mrb_gc_arena_restore(mrb, ai);
+ }
+
+ return backtrace;
+}
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 */
diff --git a/src/gc.c b/src/gc.c
index 02e058f88..e31ec2f33 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -613,14 +613,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
case MRB_TT_ENV:
{
struct REnv *e = (struct REnv*)obj;
+ mrb_int i, len;
- if (!MRB_ENV_STACK_SHARED_P(e)) {
- mrb_int i, len;
-
- len = MRB_ENV_STACK_LEN(e);
- for (i=0; i<len; i++) {
- mrb_gc_mark_value(mrb, e->stack[i]);
- }
+ len = MRB_ENV_STACK_LEN(e);
+ for (i=0; i<len; i++) {
+ mrb_gc_mark_value(mrb, e->stack[i]);
}
}
break;
@@ -725,9 +722,18 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
case MRB_TT_FIBER:
{
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
-
- if (c != mrb->root_c)
- mrb_free_context(mrb, c);
+ if (c && c != mrb->root_c) {
+ mrb_callinfo *ci = c->ci;
+ mrb_callinfo *ce = c->cibase;
+
+ while (ce <= ci) {
+ struct REnv *e = ci->env;
+ if (e && !is_dead(&mrb->gc, e) && MRB_ENV_STACK_SHARED_P(e)) {
+ mrb_env_unshare(mrb, e);
+ }
+ ci--;
+ }
+ }
}
break;
diff --git a/src/hash.c b/src/hash.c
index ac7256987..7712cd467 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -91,12 +91,6 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b)
}
}
-typedef struct {
- mrb_value v;
- mrb_int n;
-} mrb_hash_value;
-
-KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE)
KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal)
static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
diff --git a/src/load.c b/src/load.c
index da88f0d3a..d3bb281ae 100644
--- a/src/load.c
+++ b/src/load.c
@@ -614,10 +614,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
return read_irep(mrb, bin, flags);
}
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+
static void
irep_error(mrb_state *mrb)
{
- mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
+ mrb_exc_set(mrb, mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
}
MRB_API mrb_value
@@ -633,7 +635,7 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
proc = mrb_proc_new(mrb, irep);
mrb_irep_decref(mrb, irep);
if (c && c->no_exec) return mrb_obj_value(proc);
- return mrb_toplevel_run(mrb, proc);
+ return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
}
MRB_API mrb_value
@@ -695,7 +697,7 @@ mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
mrb_irep_decref(mrb, irep);
if (c && c->dump_result) mrb_codedump_all(mrb, proc);
if (c && c->no_exec) return mrb_obj_value(proc);
- val = mrb_toplevel_run(mrb, proc);
+ val = mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
return val;
}
diff --git a/src/state.c b/src/state.c
index c8c0658e4..898e77336 100644
--- a/src/state.c
+++ b/src/state.c
@@ -215,6 +215,8 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
return mrb_obj_value(ns);
}
+void mrb_free_backtrace(mrb_state *mrb);
+
MRB_API void
mrb_free_context(mrb_state *mrb, struct mrb_context *c)
{
@@ -242,6 +244,7 @@ mrb_close(mrb_state *mrb)
/* free */
mrb_gc_free_gv(mrb);
+ mrb_free_backtrace(mrb);
mrb_free_context(mrb, mrb->root_c);
mrb_free_symtbl(mrb);
mrb_alloca_free(mrb);
diff --git a/src/string.c b/src/string.c
index 6664eabd6..a3f337d4b 100644
--- a/src/string.c
+++ b/src/string.c
@@ -306,17 +306,20 @@ bytes2chars(char *p, mrb_int bi)
mrb_int i, b, n;
for (b=i=0; b<bi; i++) {
- n = utf8len(p, p+bi);
+ n = utf8len_codepage[(unsigned char)*p];
b += n;
p += n;
}
+ if (b != bi) return -1;
return i;
}
+#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value();
#else
#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
#define chars2bytes(p, off, ci) (ci)
#define bytes2chars(p, bi) (bi)
+#define BYTES_ALIGN_CHECK(pos)
#endif
static inline mrb_int
@@ -352,12 +355,12 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
return 0;
}
else if (m == 1) {
- const unsigned char *ys = y, *ye = ys + n;
- for (; y < ye; ++y) {
- if (*x == *y)
- return y - ys;
- }
- return -1;
+ const unsigned char *ys = memchr(y, *x, n);
+
+ if (ys)
+ return ys - y;
+ else
+ return -1;
}
return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
}
@@ -1608,6 +1611,7 @@ mrb_str_index(mrb_state *mrb, mrb_value str)
if (pos == -1) return mrb_nil_value();
pos = bytes2chars(RSTRING_PTR(str), pos);
+ BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
@@ -1877,6 +1881,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str)
pos = str_rindex(mrb, str, sub, pos);
if (pos >= 0) {
pos = bytes2chars(RSTRING_PTR(str), pos);
+ BYTES_ALIGN_CHECK(pos);
return mrb_fixnum_value(pos);
}
break;
diff --git a/src/symbol.c b/src/symbol.c
index c39e88012..25ae132e1 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -354,7 +354,9 @@ symname_p(const char *name)
if (*++m == '*') ++m;
break;
case '!':
- if (*++m == '=') ++m;
+ switch (*++m) {
+ case '=': case '~': ++m;
+ }
break;
case '+': case '-':
if (*++m == '@') ++m;
diff --git a/src/vm.c b/src/vm.c
index 391646017..bcea8a056 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -209,6 +209,7 @@ top_env(mrb_state *mrb, struct RProc *proc)
#define CI_ACC_SKIP -1
#define CI_ACC_DIRECT -2
+#define CI_ACC_RESUMED -3
static mrb_callinfo*
cipush(mrb_state *mrb)
@@ -237,27 +238,34 @@ cipush(mrb_state *mrb)
return ci;
}
+MRB_API void
+mrb_env_unshare(mrb_state *mrb, struct REnv *e)
+{
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+ mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
+
+ MRB_ENV_UNSHARE_STACK(e);
+ if (len > 0) {
+ stack_copy(p, e->stack, len);
+ }
+ e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
+}
+
static void
cipop(mrb_state *mrb)
{
struct mrb_context *c = mrb->c;
if (c->ci->env) {
- struct REnv *e = c->ci->env;
- size_t len = (size_t)MRB_ENV_STACK_LEN(e);
- mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
-
- MRB_ENV_UNSHARE_STACK(e);
- if (len > 0) {
- stack_copy(p, e->stack, len);
- }
- e->stack = p;
- mrb_write_barrier(mrb, (struct RBasic *)e);
+ mrb_env_unshare(mrb, c->ci->env);
}
c->ci--;
}
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
+
static void
ecall(mrb_state *mrb, int i)
{
@@ -496,21 +504,32 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
{
struct RProc *p;
mrb_callinfo *ci;
+ mrb_int max = 3;
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
- return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
+ return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
}
ci->target_class = c;
p = mrb_proc_ptr(blk);
ci->proc = p;
+ ci->argc = 1;
if (MRB_PROC_CFUNC_P(p)) {
+ stack_extend(mrb, 3, 0);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
return p->body.func(mrb, self);
}
ci->nregs = p->body.irep->nregs;
+ if (max < ci->nregs) max = ci->nregs;
+ stack_extend(mrb, max, 0);
+ mrb->c->stack[0] = self;
+ mrb->c->stack[1] = self;
+ mrb->c->stack[2] = mrb_nil_value();
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
@@ -669,7 +688,7 @@ localjump_error(mrb_state *mrb, localjump_error_kind kind)
mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
}
static void
@@ -688,7 +707,7 @@ argnum_error(mrb_state *mrb, mrb_int num)
mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
}
exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
}
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
@@ -727,11 +746,23 @@ argnum_error(mrb_state *mrb, mrb_int num)
void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
MRB_API mrb_value
-mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+{
+ mrb_irep *irep = proc->body.irep;
+
+ if (!mrb->c->stack) {
+ stack_init(mrb);
+ }
+ stack_extend(mrb, irep->nregs, stack_keep);
+ mrb->c->stack[0] = self;
+ return mrb_vm_exec(mrb, proc, irep->iseq);
+}
+
+MRB_API mrb_value
+mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{
/* mrb_assert(mrb_proc_cfunc_p(proc)) */
mrb_irep *irep = proc->body.irep;
- mrb_code *pc = irep->iseq;
mrb_value *pool = irep->pool;
mrb_sym *syms = irep->syms;
mrb_value *regs = NULL;
@@ -775,14 +806,9 @@ RETRY_TRY_BLOCK:
goto L_RAISE;
}
mrb->jmp = &c_jmp;
- if (!mrb->c->stack) {
- stack_init(mrb);
- }
- stack_extend(mrb, irep->nregs, stack_keep);
mrb->c->ci->proc = proc;
mrb->c->ci->nregs = irep->nregs;
regs = mrb->c->stack;
- regs[0] = self;
INIT_DISPATCH {
CASE(OP_NOP) {
@@ -1007,7 +1033,7 @@ RETRY_TRY_BLOCK:
CASE(OP_RAISE) {
/* A raise(R(A)) */
- mrb->exc = mrb_obj_ptr(regs[GETARG_A(i)]);
+ mrb_exc_set(mrb, regs[GETARG_A(i)]);
goto L_RAISE;
}
@@ -1124,19 +1150,24 @@ RETRY_TRY_BLOCK:
ci->nregs = n + 2;
}
result = m->body.func(mrb, recv);
- mrb->c->stack[0] = result;
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
- if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
+ if (ci->acc == CI_ACC_RESUMED) {
+ mrb->jmp = prev_jmp;
+ return result;
+ }
+ else {
+ mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
proc = ci[-1].proc;
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
}
}
+ mrb->c->stack[0] = result;
regs = mrb->c->stack = ci->stackent;
pc = ci->pc;
cipop(mrb);
@@ -1241,7 +1272,7 @@ RETRY_TRY_BLOCK:
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
recv = regs[0];
@@ -1331,7 +1362,7 @@ RETRY_TRY_BLOCK:
mrb_value exc;
exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
stack = e->stack + 1;
@@ -1561,7 +1592,7 @@ RETRY_TRY_BLOCK:
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
/* automatic yield at the end */
@@ -1601,14 +1632,19 @@ RETRY_TRY_BLOCK:
while (eidx > mrb->c->ci[-1].eidx) {
ecall(mrb, --eidx);
}
+ if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+ mrb->c->vmexec = FALSE;
+ mrb->jmp = prev_jmp;
+ return v;
+ }
cipop(mrb);
acc = ci->acc;
- pc = ci->pc;
regs = mrb->c->stack = ci->stackent;
if (acc == CI_ACC_SKIP) {
mrb->jmp = prev_jmp;
return v;
}
+ pc = ci->pc;
DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
proc = mrb->c->ci->proc;
irep = proc->body.irep;
@@ -2323,7 +2359,7 @@ RETRY_TRY_BLOCK:
/* A R(A) := target_class */
if (!mrb->c->ci->target_class) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
@@ -2381,7 +2417,7 @@ RETRY_TRY_BLOCK:
else {
exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
}
- mrb->exc = mrb_obj_ptr(exc);
+ mrb_exc_set(mrb, exc);
goto L_RAISE;
}
}
@@ -2398,30 +2434,24 @@ RETRY_TRY_BLOCK:
MRB_API 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_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
MRB_API mrb_value
-mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
+mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
mrb_callinfo *ci;
mrb_value v;
if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
- return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ return mrb_vm_run(mrb, proc, self, stack_keep);
}
ci = cipush(mrb);
ci->nregs = 1; /* protect the receiver */
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
- v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ v = mrb_vm_run(mrb, proc, self, stack_keep);
cipop(mrb);
return v;
}
-
-MRB_API mrb_value
-mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
-{
- return mrb_toplevel_run_keep(mrb, proc, 0);
-}
diff --git a/test/assert.rb b/test/assert.rb
index 6fad58fa8..e8368c64c 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -10,11 +10,7 @@ def t_print(*args)
len = args.size
while i < len
str = args[i].to_s
- begin
- __printstr__ str
- rescue NoMethodError
- __t_printstr__ str rescue print str
- end
+ __t_printstr__ str rescue print str
i += 1
end
end
diff --git a/test/t/exception.rb b/test/t/exception.rb
index d27813028..742f4a044 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -373,12 +373,47 @@ assert('Raise in ensure') do
end
end
-assert('Raise in rescue') do
- assert_raise(ArgumentError) do
- begin
- raise "" # RuntimeError
- rescue
- raise ArgumentError
+def backtrace_avaialble?
+ begin
+ raise "XXX"
+ rescue => exception
+ not exception.backtrace.empty?
+ end
+end
+
+assert('GC in rescue') do
+ skip "backtrace isn't avaialble" unless backtrace_avaialble?
+
+ line = nil
+ begin
+ [1].each do
+ [2].each do
+ [3].each do
+ line = __LINE__; raise "XXX"
+ end
+ end
+ end
+ rescue => exception
+ GC.start
+ assert_equal("#{__FILE__}:#{line}:in Object.call",
+ exception.backtrace.first)
+ end
+end
+
+assert('Method call in rescue') do
+ skip "backtrace isn't avaialble" unless backtrace_avaialble?
+
+ line = nil
+ begin
+ [1].each do
+ [2].each do
+ line = __LINE__; raise "XXX"
+ end
+ end
+ rescue => exception
+ [3].each do
end
+ assert_equal("#{__FILE__}:#{line}:in Object.call",
+ exception.backtrace.first)
end
end