[前][次][番号順一覧][スレッド一覧]

ruby-changes:46119

From: normal <ko1@a...>
Date: Sun, 2 Apr 2017 06:38:35 +0900 (JST)
Subject: [ruby-changes:46119] normal:r58233 (trunk): compile.c: optimize literal String range in case/when dispatch

normal	2017-04-02 06:38:25 +0900 (Sun, 02 Apr 2017)

  New Revision: 58233

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58233

  Log:
    compile.c: optimize literal String range in case/when dispatch
    
    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, but Ranges in case/when dispatch can be
    frozen at compile time.
    
    * 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.
      [ruby-core:80290] [Feature #13355]

  Modified files:
    trunk/compile.c
    trunk/test/ruby/test_optimization.rb
Index: test/ruby/test_optimization.rb
===================================================================
--- test/ruby/test_optimization.rb	(revision 58232)
+++ test/ruby/test_optimization.rb	(revision 58233)
@@ -495,4 +495,19 @@ EOS https://github.com/ruby/ruby/blob/trunk/test/ruby/test_optimization.rb#L495
     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
Index: compile.c
===================================================================
--- compile.c	(revision 58232)
+++ compile.c	(revision 58233)
@@ -2144,6 +2144,37 @@ iseq_peephole_optimize(rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/compile.c#L2144
 	}
     }
 
+    /*
+     * 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);
     }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]