summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby.h27
-rw-r--r--include/mruby/error.h7
-rw-r--r--include/mruby/value.h3
-rw-r--r--mrbgems/mruby-eval/src/eval.c19
-rw-r--r--mrbgems/mruby-fiber/src/fiber.c24
-rw-r--r--src/gc.c10
-rw-r--r--src/vm.c60
7 files changed, 118 insertions, 32 deletions
diff --git a/include/mruby.h b/include/mruby.h
index bd824ea91..995e1a743 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1178,6 +1178,33 @@ MRB_API void mrb_show_copyright(mrb_state *mrb);
MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
+#if 0
+/* memcpy and memset does not work with gdb reverse-next on my box */
+/* use naive memcpy and memset instead */
+#undef memcpy
+#undef memset
+static inline void*
+mrbmemcpy(void *dst, const void *src, size_t n)
+{
+ char *d = dst;
+ const char *s = src;
+ while (n--)
+ *d++ = *s++;
+ return d;
+}
+#define memcpy(a,b,c) mrbmemcpy(a,b,c)
+
+static inline void*
+mrbmemset(void *s, int c, size_t n)
+{
+ char *t = s;
+ while (n--)
+ *t++ = c;
+ return s;
+}
+#define memset(a,b,c) mrbmemset(a,b,c)
+#endif
+
MRB_END_DECL
#endif /* MRUBY_H */
diff --git a/include/mruby/error.h b/include/mruby/error.h
index bb67e7bd8..0a262550e 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -32,6 +32,13 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va
/* declaration for fail method */
MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ struct iv_tbl *iv;
+ struct RProc *proc;
+ mrb_value val;
+};
+
/**
* Protect
*
diff --git a/include/mruby/value.h b/include/mruby/value.h
index a206be549..98c68d657 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -116,7 +116,8 @@ enum mrb_vtype {
MRB_TT_DATA, /* 21 */
MRB_TT_FIBER, /* 22 */
MRB_TT_ISTRUCT, /* 23 */
- MRB_TT_MAXDEFINE /* 24 */
+ MRB_TT_BREAK, /* 24 */
+ MRB_TT_MAXDEFINE /* 25 */
};
#include <mruby/object.h>
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index 54a6aab2e..537e8541e 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -160,10 +160,7 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
cxt = mrbc_context_new(mrb);
cxt->lineno = line;
- if (!file) {
- file = "(eval)";
- }
- mrbc_filename(mrb, cxt, file);
+ mrbc_filename(mrb, cxt, file ? file : "(eval)");
cxt->capture_errors = TRUE;
cxt->no_optimize = TRUE;
@@ -178,9 +175,17 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
/* parse error */
mrb_value str;
- str = mrb_format(mrb, "line %S: %S",
- mrb_fixnum_value(p->error_buffer[0].lineno),
- mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+ if (file) {
+ str = mrb_format(mrb, " file %S line %S: %S",
+ mrb_str_new_cstr(mrb, file),
+ mrb_fixnum_value(p->error_buffer[0].lineno),
+ mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+ }
+ else {
+ str = mrb_format(mrb, " line %S: %S",
+ mrb_fixnum_value(p->error_buffer[0].lineno),
+ mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+ }
mrb_parser_free(p);
mrbc_context_free(mrb, cxt);
mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str));
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c
index 3c3630a61..8a6146dbe 100644
--- a/mrbgems/mruby-fiber/src/fiber.c
+++ b/mrbgems/mruby-fiber/src/fiber.c
@@ -74,6 +74,9 @@ fiber_init(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "&", &blk);
+ if (f->cxt) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice");
+ }
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block");
}
@@ -168,6 +171,16 @@ fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c)
}
}
+static void
+fiber_switch_context(mrb_state *mrb, struct mrb_context *c)
+{
+ if (mrb->c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib);
+ }
+ c->status = MRB_FIBER_RUNNING;
+ mrb->c = c;
+}
+
static mrb_value
fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec)
{
@@ -204,9 +217,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
else {
value = fiber_result(mrb, a, len);
}
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
- c->status = MRB_FIBER_RUNNING;
- mrb->c = c;
+ fiber_switch_context(mrb, c);
if (vmexec) {
c->vmexec = TRUE;
@@ -305,10 +316,8 @@ fiber_transfer(mrb_state *mrb, mrb_value self)
if (c == mrb->root_c) {
mrb->c->status = MRB_FIBER_TRANSFERRED;
- mrb->c = c;
- c->status = MRB_FIBER_RUNNING;
+ fiber_switch_context(mrb, c);
MARK_CONTEXT_MODIFY(c);
- mrb_write_barrier(mrb, (struct RBasic*)c->fib);
return fiber_result(mrb, a, len);
}
@@ -333,13 +342,12 @@ mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
fiber_check_cfunc(mrb, c);
c->prev->status = MRB_FIBER_RUNNING;
c->status = MRB_FIBER_SUSPENDED;
- mrb->c = c->prev;
+ fiber_switch_context(mrb, c->prev);
c->prev = NULL;
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);
}
diff --git a/src/gc.c b/src/gc.c
index 475449b2f..f74a7f31d 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -112,6 +112,7 @@ typedef struct {
struct RProc proc;
struct REnv env;
struct RException exc;
+ struct RBreak brk;
#ifdef MRB_WORD_BOXING
struct RFloat floatv;
struct RCptr cptr;
@@ -995,6 +996,7 @@ static void
final_marking_phase(mrb_state *mrb, mrb_gc *gc)
{
mark_context(mrb, mrb->c);
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
gc_mark_gray_list(mrb, gc);
mrb_assert(gc->gray_list == NULL);
gc->gray_list = gc->atomic_gray_list;
@@ -1526,13 +1528,9 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo
mrb->jmp = prev_jmp;
mrb->gc.iterating = iterating;
} MRB_CATCH(&c_jmp) {
- mrb->jmp = prev_jmp;
mrb->gc.iterating = iterating;
- if (mrb->exc) {
- mrb_value exc = mrb_obj_value(mrb->exc);
- mrb->exc = NULL;
- mrb_exc_raise(mrb, exc);
- }
+ mrb->jmp = prev_jmp;
+ MRB_THROW(prev_jmp);
} MRB_END_EXC(&c_jmp);
}
}
diff --git a/src/vm.c b/src/vm.c
index 4b121cecb..9b9cb3869 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -302,6 +302,7 @@ ecall(mrb_state *mrb, int i)
mrb_value *self = mrb->c->stack;
struct RObject *exc;
ptrdiff_t cioff;
+ int ai = mrb_gc_arena_save(mrb);
if (i<0) return;
if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
@@ -321,9 +322,13 @@ ecall(mrb_state *mrb, int i)
ci->target_class = p->target_class;
mrb->c->stack = mrb->c->stack + ci[-1].nregs;
exc = mrb->exc; mrb->exc = 0;
+ if (exc) {
+ mrb_gc_protect(mrb, mrb_obj_value(exc));
+ }
mrb_run(mrb, p, *self);
mrb->c->ci = mrb->c->cibase + cioff;
if (!mrb->exc) mrb->exc = exc;
+ mrb_gc_arena_restore(mrb, ai);
}
#ifndef MRB_FUNCALL_ARGC_MAX
@@ -755,6 +760,19 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
return mrb_exec_irep(mrb, self, p);
}
+static struct RBreak*
+break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
+{
+ struct RBreak *brk;
+
+ brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
+ brk->iv = NULL;
+ brk->proc = p;
+ brk->val = val;
+
+ return brk;
+}
+
typedef enum {
LOCALJUMP_ERROR_RETURN = 0,
LOCALJUMP_ERROR_BREAK = 1,
@@ -862,7 +880,12 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac
if (c->ci - c->cibase > cioff) {
c->ci = c->cibase + cioff;
}
- mrb->c = c;
+ if (mrb->c != c) {
+ if (mrb->c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib);
+ }
+ mrb->c = c;
+ }
return result;
}
@@ -910,6 +933,8 @@ RETRY_TRY_BLOCK:
if (exc_catched) {
exc_catched = FALSE;
+ if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK)
+ goto L_BREAK;
goto L_RAISE;
}
mrb->jmp = &c_jmp;
@@ -1185,7 +1210,9 @@ RETRY_TRY_BLOCK:
CASE(OP_RAISE) {
/* A raise(R(A)) */
- mrb_exc_set(mrb, regs[GETARG_A(i)]);
+ int a = GETARG_A(i);
+
+ mrb_exc_set(mrb, regs[a]);
goto L_RAISE;
}
@@ -1434,14 +1461,13 @@ RETRY_TRY_BLOCK:
pool = irep->pool;
syms = irep->syms;
ci->nregs = irep->nregs;
+ stack_extend(mrb, irep->nregs);
if (ci->argc < 0) {
if (irep->nregs > 3) {
- stack_extend(mrb, irep->nregs);
stack_clear(regs+3, irep->nregs-3);
}
}
else if (ci->argc+2 < irep->nregs) {
- stack_extend(mrb, irep->nregs);
stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2);
}
if (m->env) {
@@ -1813,6 +1839,9 @@ RETRY_TRY_BLOCK:
else {
struct mrb_context *c = mrb->c;
+ if (c->fib) {
+ mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+ }
mrb->c = c->prev;
c->prev = NULL;
goto L_RAISE;
@@ -1837,12 +1866,14 @@ RETRY_TRY_BLOCK:
if (ci != ci0) {
mrb->c->stack = ci[1].stackent;
}
+ stack_extend(mrb, irep->nregs);
pc = mrb->c->rescue[--ci->ridx];
}
else {
int acc;
- mrb_value v = regs[GETARG_A(i)];
+ mrb_value v;
+ v = regs[GETARG_A(i)];
mrb_gc_protect(mrb, v);
switch (GETARG_B(i)) {
case OP_R_RETURN:
@@ -1857,7 +1888,7 @@ RETRY_TRY_BLOCK:
}
ce = mrb->c->cibase + e->cioff;
- while (--ci > ce) {
+ while (ci >= ce) {
if (ci->env) {
mrb_env_unshare(mrb, ci->env);
}
@@ -1865,6 +1896,7 @@ RETRY_TRY_BLOCK:
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
+ ci--;
}
if (ce == mrb->c->cibase) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
@@ -1927,19 +1959,27 @@ RETRY_TRY_BLOCK:
}
ARENA_RESTORE(mrb, ai);
mrb->c->vmexec = FALSE;
+ mrb->exc = (struct RObject*)break_new(mrb, proc, v);
mrb->jmp = prev_jmp;
- return v;
+ MRB_THROW(prev_jmp);
+ }
+ if (FALSE) {
+ L_BREAK:
+ v = ((struct RBreak*)mrb->exc)->val;
+ proc = ((struct RBreak*)mrb->exc)->proc;
+ mrb->exc = NULL;
+ ci = mrb->c->ci;
}
mrb->c->stack = ci->stackent;
mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
while (ci > mrb->c->ci) {
+ if (ci->env) {
+ mrb_env_unshare(mrb, ci->env);
+ }
if (ci[-1].acc == CI_ACC_SKIP) {
mrb->c->ci = ci;
goto L_BREAK_ERROR;
}
- if (ci->env) {
- mrb_env_unshare(mrb, ci->env);
- }
ci--;
}
break;