From f467b02d4598ab64d98727348e8a9c4f04fc9b83 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 24 May 2020 11:44:31 +0900 Subject: Extended `OP_EXCEPT` and `OP_RAISE` (`OP_RAISEIF`) instructions - `OP_EXCEPT` checks if `mrb->exc` is `NULL`, `MRB_TT_EXCEPTION` or `MRB_TT_BREAK`. If `mrb->exc` is `NULL`, it will be replaced with `nil`. - If `OP_RAISE` is `nil`, it does nothing and the immediately following instruction is executed (like `OP_NOP`). Also, in case of `RBreak` object, it moves to the processing for `break`. With this change, the instruction name is changed from `OP_RAISE` to `OP_RAISEIF`. --- doc/opcode.md | 2 +- include/mruby/ops.h | 2 +- mrbgems/mruby-compiler/core/codegen.c | 2 +- src/codedump.c | 4 ++-- src/vm.c | 34 +++++++++++++++++++++++++++++----- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/doc/opcode.md b/doc/opcode.md index 98d29cdc0..d7e620350 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -66,7 +66,7 @@ sign) of operands. | OP_EXCEPT | B | R(a) = exc | | OP_RESCUE | BB | R(b) = R(a).isa?(R(b)) | | OP_POPERR | B | a.times{rescue_pop()} | -| OP_RAISE | B | raise(R(a)) | +| OP_RAISEIF | B | raise(R(a)) if R(a) | | OP_EPUSH | B | ensure_push(SEQ[a]) | | OP_EPOP | B | A.times{ensure_pop().call} | | OP_SENDV | BB | R(a) = call(R(a),Syms(b),*R(a+1)) | diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 7d20ac0ad..45397e2ed 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -53,7 +53,7 @@ OPCODE(ONERR, S) /* rescue_push(a) */ OPCODE(EXCEPT, B) /* R(a) = exc */ OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ OPCODE(POPERR, B) /* a.times{rescue_pop()} */ -OPCODE(RAISE, B) /* raise(R(a)) */ +OPCODE(RAISEIF, B) /* raise(R(a)) if R(a) */ OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */ OPCODE(EPOP, B) /* A.times{ensure_pop().call} */ OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index e55b6791d..7911ecb36 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1533,7 +1533,7 @@ codegen(codegen_scope *s, node *tree, int val) } if (pos1) { dispatch(s, pos1); - genop_1(s, OP_RAISE, exc); + genop_1(s, OP_RAISEIF, exc); } } pop(); diff --git a/src/codedump.c b/src/codedump.c index a19d60708..2225da4ce 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -507,8 +507,8 @@ codedump(mrb_state *mrb, const mrb_irep *irep) printf("OP_RESCUE\tR%d\tR%d", a, b); print_lv_ab(mrb, irep, a, b); break; - CASE(OP_RAISE, B); - printf("OP_RAISE\tR%d\t\t", a); + CASE(OP_RAISEIF, B); + printf("OP_RAISEIF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_POPERR, B); diff --git a/src/vm.c b/src/vm.c index 3faecfaf2..2dbbe85f8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1255,8 +1255,24 @@ RETRY_TRY_BLOCK: } CASE(OP_EXCEPT, B) { - mrb_value exc = mrb_obj_value(mrb->exc); - mrb->exc = 0; + mrb_value exc; + + if (mrb->exc == NULL) { + exc = mrb_nil_value(); + } + else { + switch (mrb->exc->tt) { + case MRB_TT_BREAK: + case MRB_TT_EXCEPTION: + exc = mrb_obj_value(mrb->exc); + break; + default: + mrb_assert(!"bad mrb_type"); + exc = mrb_nil_value(); + break; + } + mrb->exc = NULL; + } regs[a] = exc; NEXT; } @@ -1289,9 +1305,17 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_RAISE, B) { - mrb_exc_set(mrb, regs[a]); - goto L_RAISE; + CASE(OP_RAISEIF, B) { + mrb_value exc = regs[a]; + if (mrb_break_p(exc)) { + mrb->exc = mrb_obj_ptr(exc); + goto L_BREAK; + } + mrb_exc_set(mrb, exc); + if (mrb->exc) { + goto L_RAISE; + } + NEXT; } CASE(OP_EPUSH, B) { -- cgit v1.2.3