diff options
Diffstat (limited to 'wasm/setjmp.c')
-rw-r--r-- | wasm/setjmp.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/wasm/setjmp.c b/wasm/setjmp.c index 3f017e202a..1e69cb1c64 100644 --- a/wasm/setjmp.c +++ b/wasm/setjmp.c @@ -57,6 +57,7 @@ async_buf_init(struct __rb_wasm_asyncify_jmp_buf* buf) // Global unwinding/rewinding jmpbuf state static rb_wasm_jmp_buf *_rb_wasm_active_jmpbuf; +void *rb_asyncify_unwind_buf; __attribute__((noinline)) int @@ -106,6 +107,75 @@ _rb_wasm_longjmp(rb_wasm_jmp_buf* env, int value) asyncify_start_unwind(&env->longjmp_buf); } + +enum try_catch_phase { + TRY_CATCH_PHASE_MAIN = 0, + TRY_CATCH_PHASE_RESCUE = 1, +}; + +void +rb_wasm_try_catch_init(struct rb_wasm_try_catch *try_catch, + rb_wasm_try_catch_func_t try_f, + rb_wasm_try_catch_func_t catch_f, + void *context) +{ + try_catch->state = TRY_CATCH_PHASE_MAIN; + try_catch->try_f = try_f; + try_catch->catch_f = catch_f; + try_catch->context = context; +} + +// NOTE: This function is not processed by Asyncify due to a call of asyncify_stop_rewind +void +rb_wasm_try_catch_loop_run(struct rb_wasm_try_catch *try_catch, rb_wasm_jmp_buf *target) +{ + extern void *rb_asyncify_unwind_buf; + extern rb_wasm_jmp_buf *_rb_wasm_active_jmpbuf; + + target->state = JMP_BUF_STATE_CAPTURED; + + switch ((enum try_catch_phase)try_catch->state) { + case TRY_CATCH_PHASE_MAIN: { + // may unwind + try_catch->try_f(try_catch->context); + break; + } + case TRY_CATCH_PHASE_RESCUE: { + if (try_catch->catch_f) { + // may unwind + try_catch->catch_f(try_catch->context); + } + break; + } + } + + while (1) { + // catch longjmp with target jmp_buf + if (rb_asyncify_unwind_buf && _rb_wasm_active_jmpbuf == target) { + // do similar steps setjmp does when JMP_BUF_STATE_RETURNING + + // stop unwinding + // (but call stop_rewind to update the asyncify state to "normal" from "unwind") + asyncify_stop_rewind(); + // clear the active jmpbuf because it's already stopped + _rb_wasm_active_jmpbuf = NULL; + // reset jmpbuf state to be able to unwind again + target->state = JMP_BUF_STATE_CAPTURED; + // move to catch loop phase + try_catch->state = TRY_CATCH_PHASE_RESCUE; + if (try_catch->catch_f) { + try_catch->catch_f(try_catch->context); + } + continue; + } else if (rb_asyncify_unwind_buf /* unrelated unwind */) { + return; + } + // no unwind, then exit + break; + } + return; +} + void * rb_wasm_handle_jmp_unwind(void) { |