Share duplicate code between Wasm and the others

This commit is contained in:
Nobuyoshi Nakada 2023-08-06 23:34:27 +09:00
parent 1a83474ded
commit 694d99dda2
No known key found for this signature in database
GPG Key ID: 3582D74E1FEE4465
Notes: git 2023-08-08 00:37:57 +00:00

112
vm.c
View File

@ -2298,69 +2298,53 @@ hook_before_rewind(rb_execution_context_t *ec, const rb_control_frame_t *cfp,
static inline VALUE static inline VALUE
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo); vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo);
static inline VALUE
vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state, struct rb_vm_tag *tag, VALUE result);
// for non-Emscripten Wasm build, use vm_exec with optimized setjmp for runtime performance // for non-Emscripten Wasm build, use vm_exec with optimized setjmp for runtime performance
#if defined(__wasm__) && !defined(__EMSCRIPTEN__) #if defined(__wasm__) && !defined(__EMSCRIPTEN__)
struct rb_vm_exec_context { struct rb_vm_exec_context {
rb_execution_context_t *ec; rb_execution_context_t *const ec;
struct rb_vm_tag *tag; struct rb_vm_tag *const tag;
VALUE result; VALUE result;
enum ruby_tag_type state;
}; };
static void
vm_exec_enter_vm_loop(rb_execution_context_t *ec, struct rb_vm_exec_context *ctx,
struct rb_vm_tag *_tag, bool skip_first_ex_handle)
{
if (skip_first_ex_handle) {
goto vm_loop_start;
}
ctx->result = ec->errinfo;
rb_ec_raised_reset(ec, RAISED_STACKOVERFLOW | RAISED_NOMEMORY);
while (UNDEF_P(ctx->result = vm_exec_handle_exception(ec, ctx->state, ctx->result))) {
/* caught a jump, exec the handler */
ctx->result = vm_exec_core(ec);
vm_loop_start:
VM_ASSERT(ec->tag == _tag);
/* when caught `throw`, `tag.state` is set. */
if ((ctx->state = _tag->state) == TAG_NONE) break;
_tag->state = TAG_NONE;
}
}
static void static void
vm_exec_bottom_main(void *context) vm_exec_bottom_main(void *context)
{ {
struct rb_vm_exec_context *ctx = (struct rb_vm_exec_context *)context; struct rb_vm_exec_context *ctx = context;
rb_execution_context_t *ec = ctx->ec;
ctx->state = TAG_NONE; ctx->result = vm_exec_loop(ec, TAG_NONE, ctx->tag, vm_exec_core(ec));
ctx->result = vm_exec_core(ctx->ec);
vm_exec_enter_vm_loop(ctx->ec, ctx, ctx->tag, true);
} }
static void static void
vm_exec_bottom_rescue(void *context) vm_exec_bottom_rescue(void *context)
{ {
struct rb_vm_exec_context *ctx = (struct rb_vm_exec_context *)context; struct rb_vm_exec_context *ctx = context;
ctx->state = rb_ec_tag_state(ctx->ec); rb_execution_context_t *ec = ctx->ec;
vm_exec_enter_vm_loop(ctx->ec, ctx, ctx->tag, false);
ctx->result = vm_exec_loop(ec, rb_ec_tag_state(ec), ctx->tag, ec->errinfo);
} }
#endif
VALUE VALUE
vm_exec(rb_execution_context_t *ec) vm_exec(rb_execution_context_t *ec)
{ {
struct rb_vm_exec_context ctx = { VALUE result = Qundef;
.ec = ec,
.result = Qundef,
};
struct rb_wasm_try_catch try_catch;
EC_PUSH_TAG(ec); EC_PUSH_TAG(ec);
_tag.retval = Qnil; _tag.retval = Qnil;
ctx.tag = &_tag;
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
struct rb_vm_exec_context ctx = {
.ec = ec,
.tag = &_tag,
};
struct rb_wasm_try_catch try_catch;
EC_REPUSH_TAG(); EC_REPUSH_TAG();
@ -2368,44 +2352,46 @@ vm_exec(rb_execution_context_t *ec)
rb_wasm_try_catch_loop_run(&try_catch, &_tag.buf); rb_wasm_try_catch_loop_run(&try_catch, &_tag.buf);
EC_POP_TAG(); result = ctx.result;
return ctx.result;
}
#else #else
VALUE
vm_exec(rb_execution_context_t *ec)
{
enum ruby_tag_type state; enum ruby_tag_type state;
VALUE result = Qundef;
EC_PUSH_TAG(ec);
_tag.retval = Qnil;
if ((state = EC_EXEC_TAG()) == TAG_NONE) { if ((state = EC_EXEC_TAG()) == TAG_NONE) {
if (UNDEF_P(result = jit_exec(ec))) { if (UNDEF_P(result = jit_exec(ec))) {
result = vm_exec_core(ec); result = vm_exec_core(ec);
} }
goto vm_loop_start; /* fallback to the VM */ /* fallback to the VM */
result = vm_exec_loop(ec, TAG_NONE, &_tag, result);
} }
else { else {
result = ec->errinfo; result = vm_exec_loop(ec, state, &_tag, ec->errinfo);
rb_ec_raised_reset(ec, RAISED_STACKOVERFLOW | RAISED_NOMEMORY);
while (UNDEF_P(result = vm_exec_handle_exception(ec, state, result))) {
/* caught a jump, exec the handler */
result = vm_exec_core(ec);
vm_loop_start:
VM_ASSERT(ec->tag == &_tag);
/* when caught `throw`, `tag.state` is set. */
if ((state = _tag.state) == TAG_NONE) break;
_tag.state = TAG_NONE;
}
} }
#endif
EC_POP_TAG(); EC_POP_TAG();
return result; return result;
} }
#endif
static inline VALUE
vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state,
struct rb_vm_tag *tag, VALUE result)
{
if (state == TAG_NONE) { /* no jumps, result is discarded */
goto vm_loop_start;
}
rb_ec_raised_reset(ec, RAISED_STACKOVERFLOW | RAISED_NOMEMORY);
while (UNDEF_P(result = vm_exec_handle_exception(ec, state, result))) {
/* caught a jump, exec the handler */
result = vm_exec_core(ec);
vm_loop_start:
VM_ASSERT(ec->tag == tag);
/* when caught `throw`, `tag.state` is set. */
if ((state = tag->state) == TAG_NONE) break;
tag->state = TAG_NONE;
}
return result;
}
static inline VALUE static inline VALUE
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo) vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo)