aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compile.c31
-rw-r--r--test/ruby/test_optimization.rb15
2 files changed, 46 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index 317475b525..81cbb9ff5a 100644
--- a/compile.c
+++ b/compile.c
@@ -2144,6 +2144,37 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
+ /*
+ * putstring "beg"
+ * putstring "end"
+ * newrange excl
+ *
+ * ==>
+ *
+ * putobject "beg".."end"
+ */
+ if (IS_INSN_ID(iobj, checkmatch)) {
+ INSN *range = (INSN *)get_prev_insn(iobj);
+ INSN *beg, *end;
+
+ if (range && IS_INSN_ID(range, newrange) &&
+ (end = (INSN *)get_prev_insn(range)) != 0 &&
+ IS_INSN_ID(end, putstring) &&
+ (beg = (INSN *)get_prev_insn(end)) != 0 &&
+ IS_INSN_ID(beg, putstring)) {
+ VALUE str_beg = OPERAND_AT(beg, 0);
+ VALUE str_end = OPERAND_AT(end, 0);
+ int excl = FIX2INT(OPERAND_AT(range, 0));
+ VALUE lit_range = rb_range_new(str_beg, str_end, excl);
+
+ iseq_add_mark_object(iseq, lit_range);
+ REMOVE_ELEM(&beg->link);
+ REMOVE_ELEM(&end->link);
+ range->insn_id = BIN(putobject);
+ OPERAND_AT(range, 0) = lit_range;
+ }
+ }
+
if (IS_INSN_ID(iobj, leave)) {
remove_unreachable_chunk(iseq, iobj->link.next);
}
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 7c8990fde8..2de1db340f 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -495,4 +495,19 @@ EOS
bug11816 = '[ruby-core:74993] [Bug #11816]'
assert_ruby_status([], 'nil&.foo &&= false', bug11816)
end
+
+ def test_peephole_string_literal_range
+ code = <<-EOF
+ case ver
+ when "2.0.0".."2.3.2" then :foo
+ when "1.8.0"..."1.8.8" then :bar
+ end
+ EOF
+ iseq = RubyVM::InstructionSequence.compile(code)
+ insn = iseq.disasm
+ assert_match %r{putobject\s+#{Regexp.quote('"1.8.0"..."1.8.8"')}}, insn
+ assert_match %r{putobject\s+#{Regexp.quote('"2.0.0".."2.3.2"')}}, insn
+ assert_no_match /putstring/, insn
+ assert_no_match /newrange/, insn
+ end
end