From 2b72d8a7c153e2afb22245ad9e40e0c7d5b1aa70 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Dec 2025 20:12:28 +0900 Subject: [PATCH] mruby-compiler: optimize JMPNOT+JMP to JMPIF in pattern matching For patterns with a single failure check (like `1 => String`), invert JMPNOT to JMPIF and eliminate the following JMP instruction. Before: JMPNOT fail; JMP end; fail: error; end: (8 bytes for jumps) After: JMPIF end; error; end: (4 bytes for jump) The optimization only applies when: 1. There's exactly one JMPNOT in the failure chain 2. The JMPNOT is immediately before the JMP (no code between) Co-authored-by: Claude --- mrbgems/mruby-compiler/core/codegen.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 53844bff8..380c4f7a4 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -6402,10 +6402,23 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_LOADT, cursp()); push(); } - match_pos = genjmp(s, OP_JMP, JMPLINK_START); + + /* Optimize: single JMPNOT can be inverted to JMPIF, eliminating JMP */ + /* Conditions: (1) single entry in fail_pos chain, and + * (2) JMPNOT is immediately before current position (no code between) */ + if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 && + fail_pos + 2 == s->pc) { + /* Single failure point - invert JMPNOT to JMPIF */ + s->iseq[fail_pos - 2] = OP_JMPIF; + match_pos = fail_pos; + } + else { + /* Multiple failure points - need JMP to skip error handling */ + match_pos = genjmp(s, OP_JMP, JMPLINK_START); + dispatch_linked(s, fail_pos); + } /* Pattern failed */ - dispatch_linked(s, fail_pos); pop(); /* pop the value */ if (mp->raise_on_fail) { /* expr => pattern: raise NoMatchingPatternError */