Skip to content

Commit

Permalink
Share duplicate code between Wasm and the others
Browse files Browse the repository at this point in the history
  • Loading branch information
nobu committed Aug 6, 2023
1 parent 561eb67 commit 5b1b650
Showing 1 changed file with 43 additions and 59 deletions.
102 changes: 43 additions & 59 deletions vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2299,113 +2299,97 @@ hook_before_rewind(rb_execution_context_t *ec, const rb_control_frame_t *cfp,
static inline VALUE
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo);

// for non-Emscripten Wasm build, use vm_exec with optimized setjmp for runtime performance
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)

struct rb_vm_exec_context {
rb_execution_context_t *ec;
struct rb_vm_tag *tag;
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)
static VALUE
vm_exec_loop(rb_execution_context_t *ec, enum ruby_tag_type state,
struct rb_vm_tag *_tag, VALUE result)
{
if (skip_first_ex_handle) {
if (state == TAG_NONE) { /* no jumps, result is discarded */
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))) {
while (UNDEF_P(result = vm_exec_handle_exception(ec, state, result))) {
/* caught a jump, exec the handler */
ctx->result = vm_exec_core(ec);
vm_loop_start:
vm_loop_start:
result = vm_exec_core(ec);
VM_ASSERT(ec->tag == _tag);
/* when caught `throw`, `tag.state` is set. */
if ((ctx->state = _tag->state) == TAG_NONE) break;
if ((state = _tag->state) == TAG_NONE) break;
_tag->state = TAG_NONE;
}

return result;
}

struct rb_vm_exec_context {
rb_execution_context_t *const ec;
struct rb_vm_tag *const tag;

VALUE result;
};

// for non-Emscripten Wasm build, use vm_exec with optimized setjmp for runtime performance
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)

static void
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_core(ctx->ec);
vm_exec_enter_vm_loop(ctx->ec, ctx, ctx->tag, true);
ctx->result = vm_exec_loop(ec, TAG_NONE, ctx->tag, Qundef);
}

static void
vm_exec_bottom_rescue(void *context)
{
struct rb_vm_exec_context *ctx = (struct rb_vm_exec_context *)context;
ctx->state = rb_ec_tag_state(ctx->ec);
vm_exec_enter_vm_loop(ctx->ec, ctx, ctx->tag, false);
struct rb_vm_exec_context *ctx = context;
rb_execution_context_t *ec = ctx->ec;

ctx->result = vm_exec_loop(ec, rb_ec_tag_state(ec), ctx->tag, ec->errinfo);
}
#endif

VALUE
vm_exec(rb_execution_context_t *ec)
{
VALUE result = Qundef;

EC_PUSH_TAG(ec);

struct rb_vm_exec_context ctx = {
.ec = ec,
.result = Qundef,
.tag = &_tag,
};
struct rb_wasm_try_catch try_catch;

EC_PUSH_TAG(ec);

_tag.retval = Qnil;
ctx.tag = &_tag;

#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
struct rb_wasm_try_catch try_catch;

EC_REPUSH_TAG();

rb_wasm_try_catch_init(&try_catch, vm_exec_bottom_main, vm_exec_bottom_rescue, &ctx);

rb_wasm_try_catch_loop_run(&try_catch, &_tag.buf);

EC_POP_TAG();
return ctx.result;
}

result = ctx.result;
#else

VALUE
vm_exec(rb_execution_context_t *ec)
{
enum ruby_tag_type state;
VALUE result = Qundef;

EC_PUSH_TAG(ec);

_tag.retval = Qnil;
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
if (UNDEF_P(result = jit_exec(ec))) {
result = vm_exec_core(ec);
if (UNDEF_P(result = jit_exec(ctx.ec))) {
/* fallback to the VM */
result = vm_exec_loop(ctx.ec, TAG_NONE, ctx.tag, Qundef);
}
goto vm_loop_start; /* fallback to the VM */
}
else {
result = 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;
}
result = vm_exec_loop(ctx.ec, state, ctx.tag, ctx.ec->errinfo);
}
#endif

EC_POP_TAG();
return result;
}
#endif

static inline VALUE
vm_exec_handle_exception(rb_execution_context_t *ec, enum ruby_tag_type state, VALUE errinfo)
Expand Down

0 comments on commit 5b1b650

Please sign in to comment.