diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-04-19 22:34:20 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-04-19 22:34:20 +0900 |
| commit | ff366b65ebc866a6287002ece5121f6f25321e26 (patch) | |
| tree | e754c81cdf798dc2b8ead74192154bc30a918e9f /src/vm.c | |
| parent | 9d362f2c2732b15341f76d2d51bbd946b28e5974 (diff) | |
| parent | 891e852286dabdc2dfda70b00d5325546a939a62 (diff) | |
| download | mruby-ff366b65ebc866a6287002ece5121f6f25321e26.tar.gz mruby-ff366b65ebc866a6287002ece5121f6f25321e26.zip | |
Merge pull request #5415 from dearblue/unwind-mrb_protect
Introducing the `mrb_protect_raw()` API function
Diffstat (limited to 'src/vm.c')
| -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); |
