summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authordearblue <[email protected]>2020-07-18 19:05:12 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2020-10-12 16:21:33 +0900
commitc1f112c49a597da8478516261f0812bc073f6cd8 (patch)
treec5f7f8d805f7bf767a06a10e9b7ef82071cfcee2 /include
parent0d7b4deccf445e3edae9239bf40b91cc79e83634 (diff)
downloadmruby-c1f112c49a597da8478516261f0812bc073f6cd8.tar.gz
mruby-c1f112c49a597da8478516261f0812bc073f6cd8.zip
Replace global jump with catch handler implementation
When a global jump occurs, look at the catch handler table to determine where to jump. In that case, `pc` already shows the following instruction, but since the table shows `begin_offset ... end_offset`, the comparison is done with `begin_offset < pc && pc <= end_offset`. If there is a corresponding handler, move `pc` to `handler.target_offset` and continue running the VM. When a global jump across `ensure` is made by `return`, `break`, `next`, `redo` and `retry`, the extended `RBreak` object saves and restores the C-level execution position. This extended `RBreak` can have tag information, which makes it a pseudo coroutine (the "tag" mimics CRuby). The implementation of pseudo coroutines by `RBreak` is summarized by `CHECKPOINT_RESTORE ... CHECKPOINT_MAIN ... CHECKPOINT_END` and `throw_tagged_break` / `unwind_ensure` macros. The restart of processing is branched by `RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS)`. - Not only `rescue` blocks but also `ensure` blocks are now sandwiched between `OP_EXCEPT` and `OP_RAISEIF`. - Remove the function `ecall()`. It is no longer necessary to re-enter the VM to perform an "ensure block". This will resolves #1888. - Added instruction `OP_JUW` (Jump while UnWind). It jumps unconditionally like `OP_JMP`, but searches the catch handler table and executes the ensure block. Since it searches the catch handler table, it is much heavier than `OP_JMP`.
Diffstat (limited to 'include')
-rw-r--r--include/mruby.h8
-rw-r--r--include/mruby/error.h33
-rw-r--r--include/mruby/ops.h1
3 files changed, 34 insertions, 8 deletions
diff --git a/include/mruby.h b/include/mruby.h
index c9425e8a7..9f1d1aa30 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -149,8 +149,6 @@ typedef struct {
mrb_sym mid;
const struct RProc *proc;
mrb_value *stackent;
- uint16_t ridx;
- uint16_t epos;
struct REnv *env;
const mrb_code *pc; /* return address */
const mrb_code *err; /* error position */
@@ -177,11 +175,6 @@ struct mrb_context {
mrb_callinfo *ci;
mrb_callinfo *cibase, *ciend;
- uint16_t *rescue; /* exception handler stack */
- uint16_t rsize;
- struct RProc **ensure; /* ensure handler stack */
- uint16_t esize, eidx;
-
enum mrb_fiber_state status : 4;
mrb_bool vmexec : 1;
struct RFiber *fib;
@@ -301,7 +294,6 @@ typedef struct mrb_state {
mrb_atexit_func *atexit_stack;
#endif
uint16_t atexit_stack_len;
- uint16_t ecall_nest; /* prevent infinite recursive ecall() */
} mrb_state;
/**
diff --git a/include/mruby/error.h b/include/mruby/error.h
index 72f6c5f3d..67a0a539e 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -66,6 +66,39 @@ mrb_break_value_set(struct RBreak *brk, mrb_value val)
#define mrb_break_proc_get(brk) ((brk)->proc)
#define mrb_break_proc_set(brk, p) ((brk)->proc = p)
+#define RBREAK_TAG_FOREACH(f) \
+ f(RBREAK_TAG_BREAK, 0) \
+ f(RBREAK_TAG_BREAK_UPPER, 1) \
+ f(RBREAK_TAG_BREAK_INTARGET, 2) \
+ f(RBREAK_TAG_RETURN_BLOCK, 3) \
+ f(RBREAK_TAG_RETURN, 4) \
+ f(RBREAK_TAG_RETURN_TOPLEVEL, 5) \
+ f(RBREAK_TAG_JUMP, 6) \
+ f(RBREAK_TAG_STOP, 7)
+
+#define RBREAK_TAG_DEFINE(tag, i) tag = i,
+enum {
+ RBREAK_TAG_FOREACH(RBREAK_TAG_DEFINE)
+};
+#undef RBREAK_TAG_DEFINE
+
+#define RBREAK_TAG_BIT 3
+#define RBREAK_TAG_BIT_OFF 8
+#define RBREAK_TAG_MASK (~(~UINT32_C(0) << RBREAK_TAG_BIT))
+
+static inline uint32_t
+mrb_break_tag_get(struct RBreak *brk)
+{
+ return (brk->flags >> RBREAK_TAG_BIT_OFF) & RBREAK_TAG_MASK;
+}
+
+static inline void
+mrb_break_tag_set(struct RBreak *brk, uint32_t tag)
+{
+ brk->flags &= ~(RBREAK_TAG_MASK << RBREAK_TAG_BIT_OFF);
+ brk->flags |= (tag & RBREAK_TAG_MASK) << RBREAK_TAG_BIT_OFF;
+}
+
/**
* Protect
*
diff --git a/include/mruby/ops.h b/include/mruby/ops.h
index 8ff44088e..770e54f3d 100644
--- a/include/mruby/ops.h
+++ b/include/mruby/ops.h
@@ -49,6 +49,7 @@ OPCODE(JMP, S) /* pc=a */
OPCODE(JMPIF, BS) /* if R(a) pc=b */
OPCODE(JMPNOT, BS) /* if !R(a) pc=b */
OPCODE(JMPNIL, BS) /* if R(a)==nil pc=b */
+OPCODE(JUW, S) /* unwind_and_jump_to(a) */
OPCODE(EXCEPT, B) /* R(a) = exc */
OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */
OPCODE(RAISEIF, B) /* raise(R(a)) if R(a) */