dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] compile.c: optimize literal String range in case/when dispatch
@ 2017-03-23  8:20 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2017-03-23  8:20 UTC (permalink / raw)
  To: spew

This is similar in spirit to opt_case_dispatch as the literal
Range here is guaranteed to be immutable when used for
checkmatch.

Normal range literals with non-frozen strings are actually
mutable, as Range#begin and Range#end exposes the strings to
modification.  So those Range objects cannot be frozen without
breaking compatibility.

* compile.c (iseq_peephole_optimize): persistent Range creation
  when String literals are used as beginning and end of range
  when used for case/when dispatch.
---
 compile.c                      | 31 +++++++++++++++++++++++++++++++
 test/ruby/test_optimization.rb | 15 +++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/compile.c b/compile.c
index e3d66b6809..496e4d8857 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 sbeg = OPERAND_AT(beg, 0);
+	    VALUE send = OPERAND_AT(end, 0);
+	    int excl = FIX2INT(OPERAND_AT(range, 0));
+	    VALUE lit_range = rb_range_new(sbeg, send, excl);
+
+	    iseq_add_mark_object_compile_time(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 502d12389e..aa3c82fdfd 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -490,4 +490,19 @@ def test_nil_safe_conditional_assign
     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
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2017-03-23  8:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-23  8:20 [PATCH] compile.c: optimize literal String range in case/when dispatch Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).