mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: do not flip + and - opcode for negative literal
The peephole in gen_addsub() rewrote `q + -n` into OP_SUBI n (and `q - -n` into OP_ADDI n) by negating n. For numeric receivers this is equivalent, but for receivers overriding + or - the runtime fallback dispatches the flipped method, losing the original operator. Restrict the fold to non-negative immediates; negative falls through to the normal OP_ADD/OP_SUB path with LOADI of the literal value. close #2557 ref #2579 Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1457,19 +1457,13 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
|
||||
struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));
|
||||
mrb_int n0;
|
||||
if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data0, &n0)) {
|
||||
/* OP_ADDI/OP_SUBI takes upto 8bits */
|
||||
if (n > UINT8_MAX || n < -UINT8_MAX) goto normal;
|
||||
/* Fold to OP_ADDI/OP_SUBI only for non-negative 8-bit n; flipping op
|
||||
for negative n would change the method sent on user override (#2557). */
|
||||
if (n < 0 || n > UINT8_MAX) goto normal;
|
||||
rewind_pc(s);
|
||||
if (n == 0) return;
|
||||
if (n > 0) {
|
||||
if (op == OP_ADD) genop_2(s, OP_ADDI, dst, (uint16_t)n);
|
||||
else genop_2(s, OP_SUBI, dst, (uint16_t)n);
|
||||
}
|
||||
else { /* n < 0 */
|
||||
n = -n;
|
||||
if (op == OP_ADD) genop_2(s, OP_SUBI, dst, (uint16_t)n);
|
||||
else genop_2(s, OP_ADDI, dst, (uint16_t)n);
|
||||
}
|
||||
if (op == OP_ADD) genop_2(s, OP_ADDI, dst, (uint16_t)n);
|
||||
else genop_2(s, OP_SUBI, dst, (uint16_t)n);
|
||||
return;
|
||||
}
|
||||
if (op == OP_ADD) {
|
||||
|
||||
@@ -383,4 +383,20 @@ qwe]
|
||||
assert_equal :'{foo bar}', h
|
||||
end
|
||||
|
||||
assert('operator override with negative integer literal', '#2557') do
|
||||
cls = Class.new {
|
||||
def +(x); ['add', x]; end
|
||||
def -(x); ['sub', x]; end
|
||||
}
|
||||
q = cls.new
|
||||
assert_equal ['add', 5], q + 5
|
||||
assert_equal ['add', -5], q + -5
|
||||
assert_equal ['sub', 5], q - 5
|
||||
assert_equal ['sub', -5], q - -5
|
||||
assert_equal ['add', 500], q + 500
|
||||
assert_equal ['add', -500], q + -500
|
||||
assert_equal ['sub', 500], q - 500
|
||||
assert_equal ['sub', -500], q - -500
|
||||
end
|
||||
|
||||
# Not Implemented ATM assert('Literals Regular expression', '8.7.6.5') do
|
||||
|
||||
Reference in New Issue
Block a user