diff --git a/compile.c b/compile.c index e3d66b6809..317475b525 100644 --- a/compile.c +++ b/compile.c @@ -5211,7 +5211,12 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) { VALUE str = rb_fstring(node->nd_recv->nd_lit); iseq_add_mark_object(iseq, str); - ADD_INSN1(ret, line, opt_str_freeze, str); + if (node->nd_mid == idUMinus) { + ADD_INSN1(ret, line, opt_str_uminus, str); + } + else { + ADD_INSN1(ret, line, opt_str_freeze, str); + } if (popped) { ADD_INSN(ret, line, pop); } diff --git a/insns.def b/insns.def index 9bae14b5a9..a4f2526bef 100644 --- a/insns.def +++ b/insns.def @@ -981,6 +981,20 @@ opt_str_freeze } } +DEFINE_INSN +opt_str_uminus +(VALUE str) +() +(VALUE val) +{ + if (BASIC_OP_UNREDEFINED_P(BOP_UMINUS, STRING_REDEFINED_OP_FLAG)) { + val = str; + } + else { + val = rb_funcall(rb_str_resurrect(str), idUMinus, 0); + } +} + DEFINE_INSN opt_newarray_max (rb_num_t num) diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 502d12389e..7c8990fde8 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -104,6 +104,11 @@ class TestRubyOptimization < Test::Unit::TestCase assert_redefine_method('String', 'freeze', 'assert_nil "foo".freeze') end + def test_string_uminus + assert_same "foo".freeze, -"foo" + assert_redefine_method('String', '-@', 'assert_nil(-"foo")') + end + def test_string_freeze_saves_memory n = 16384 data = '.'.freeze diff --git a/vm.c b/vm.c index 1eefee18a6..9ece1b8c3d 100644 --- a/vm.c +++ b/vm.c @@ -1569,6 +1569,7 @@ vm_init_redefined_flag(void) OP(Succ, SUCC), (C(Integer), C(String), C(Time)); OP(EqTilde, MATCH), (C(Regexp), C(String)); OP(Freeze, FREEZE), (C(String)); + OP(UMinus, UMINUS), (C(String)); OP(Max, MAX), (C(Array)); OP(Min, MIN), (C(Array)); #undef C diff --git a/vm_core.h b/vm_core.h index 5b930a8aa7..437c4d9c2d 100644 --- a/vm_core.h +++ b/vm_core.h @@ -454,6 +454,7 @@ enum ruby_basic_operators { BOP_NEQ, BOP_MATCH, BOP_FREEZE, + BOP_UMINUS, BOP_MAX, BOP_MIN,