diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/vm.c | 43 |
1 files changed, 43 insertions, 0 deletions
@@ -306,6 +306,49 @@ cipop(mrb_state *mrb) return c->ci; } +MRB_API mrb_value +mrb_protect_raw(mrb_state *mrb, mrb_protect_raw_func *body, void *userdata, mrb_bool *error) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result = mrb_nil_value(); + int ai = mrb_gc_arena_save(mrb); + const struct mrb_context *c = mrb->c; + int ci_index = c->ci - c->cibase; + + if (error) { *error = FALSE; } + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, userdata); + mrb->jmp = prev_jmp; + } + MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + result = mrb_obj_value(mrb->exc); + mrb->exc = NULL; + if (error) { *error = TRUE; } + if (mrb->c == c) { + while (c->ci - c->cibase > ci_index) { + cipop(mrb); + } + } + else { + // It was probably switched by mrb_fiber_resume(). + // Simply destroy all successive CI_ACC_DIRECTs once the fiber has been switched. + c = mrb->c; + while (c->ci > c->cibase && c->ci->acc == CI_ACC_DIRECT) { + cipop(mrb); + } + } + } + MRB_END_EXC(&c_jmp); + + mrb_gc_arena_restore(mrb, ai); + mrb_gc_protect(mrb, result); + return result; +} + void mrb_exc_set(mrb_state *mrb, mrb_value exc); static mrb_value mrb_run(mrb_state *mrb, const struct RProc* proc, mrb_value self); |
