diff options
| -rw-r--r-- | include/mruby.h | 27 | ||||
| -rw-r--r-- | include/mruby/error.h | 7 | ||||
| -rw-r--r-- | include/mruby/value.h | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 19 | ||||
| -rw-r--r-- | mrbgems/mruby-fiber/src/fiber.c | 24 | ||||
| -rw-r--r-- | src/gc.c | 10 | ||||
| -rw-r--r-- | src/vm.c | 60 |
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); } @@ -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); } } @@ -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; |
