mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
vm: fuse JMPIF and MATCHERR into conditional MATCHERR
Change OP_MATCHERR from Z format (unconditional) to B format (conditional on register). This allows fusing JMPIF + MATCHERR sequence into a single MATCHERR instruction for simple patterns. Before: JMPIF R2 target (4 bytes) + MATCHERR (1 byte) = 5 bytes After: MATCHERR R2 (2 bytes) Saves 3 bytes per pattern match with raise_on_fail. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -57,7 +57,7 @@ OPCODE(JMPUW, 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] */
|
||||
OPCODE(MATCHERR, Z) /* raise NoMatchingPatternError */
|
||||
OPCODE(MATCHERR, B) /* raise NoMatchingPatternError unless R[a] */
|
||||
OPCODE(SSEND, BBB) /* R[a] = self.send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..) (c=n|k<<4) */
|
||||
OPCODE(SSENDB, BBB) /* R[a] = self.send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..,&R[a+n+2k+1]) */
|
||||
OPCODE(SEND, BBB) /* R[a] = R[a].send(Syms[b],R[a+1]..,R[a+n+1]:R[a+n+2]..) (c=n|k<<4) */
|
||||
|
||||
@@ -6625,14 +6625,24 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
}
|
||||
|
||||
/* Optimize: single JMPNOT can be inverted to JMPIF, eliminating JMP */
|
||||
/* Optimize: single JMPNOT can be replaced with MATCHERR for raise_on_fail */
|
||||
/* Conditions: (1) single entry in fail_pos chain,
|
||||
* (2) JMPNOT is immediately before current position (no code between), and
|
||||
* (3) the instruction is actually JMPNOT (not JMP from undefined pinned var) */
|
||||
if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 &&
|
||||
fail_pos + 2 == s->pc &&
|
||||
s->iseq[fail_pos - 2] == OP_JMPNOT) {
|
||||
/* Single failure point - invert JMPNOT to JMPIF */
|
||||
if (mp->raise_on_fail) {
|
||||
/* Single failure point with raise - replace JMPNOT with MATCHERR */
|
||||
int reg = s->iseq[fail_pos - 1]; /* Register from JMPNOT */
|
||||
s->pc = fail_pos - 2; /* Rewind past JMPNOT */
|
||||
s->lastpc = s->pc;
|
||||
genop_1(s, OP_MATCHERR, reg); /* Emit MATCHERR with the register */
|
||||
s->sp = saved_sp - 1;
|
||||
if (val) push();
|
||||
break; /* Pattern matching complete */
|
||||
}
|
||||
/* Single failure point with 'in' pattern - invert JMPNOT to JMPIF */
|
||||
s->iseq[fail_pos - 2] = OP_JMPIF;
|
||||
match_pos = fail_pos;
|
||||
}
|
||||
@@ -6647,7 +6657,8 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
pop(); /* pop the value */
|
||||
if (mp->raise_on_fail) {
|
||||
/* expr => pattern: raise NoMatchingPatternError */
|
||||
genop_0(s, OP_MATCHERR);
|
||||
genop_1(s, OP_LOADF, cursp()); /* Load false for MATCHERR */
|
||||
genop_1(s, OP_MATCHERR, cursp());
|
||||
}
|
||||
else {
|
||||
/* expr in pattern: return false */
|
||||
|
||||
+2
-2
@@ -572,8 +572,8 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out)
|
||||
fprintf(out, "RAISEIF\tR%d\t", a);
|
||||
print_lv_a(mrb, irep, a, out);
|
||||
break;
|
||||
CASE(OP_MATCHERR, Z):
|
||||
fprintf(out, "MATCHERR\n");
|
||||
CASE(OP_MATCHERR, B):
|
||||
fprintf(out, "MATCHERR\tR%d\n", a);
|
||||
break;
|
||||
|
||||
CASE(OP_DEBUG, BBB):
|
||||
|
||||
@@ -2167,8 +2167,11 @@ RETRY_TRY_BLOCK:
|
||||
NEXT;
|
||||
}
|
||||
|
||||
CASE(OP_MATCHERR, Z) {
|
||||
RAISE_LIT(mrb, mrb_exc_get_id(mrb, MRB_ERROR_SYM(NoMatchingPatternError)), "pattern not matched");
|
||||
CASE(OP_MATCHERR, B) {
|
||||
if (!mrb_test(regs[a])) {
|
||||
RAISE_LIT(mrb, mrb_exc_get_id(mrb, MRB_ERROR_SYM(NoMatchingPatternError)), "pattern not matched");
|
||||
}
|
||||
NEXT;
|
||||
}
|
||||
|
||||
CASE(OP_SSEND, BBB) {
|
||||
|
||||
Reference in New Issue
Block a user