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

ruby-changes:40156

From: nobu <ko1@a...>
Date: Fri, 23 Oct 2015 11:58:29 +0900 (JST)
Subject: [ruby-changes:40156] nobu:r52237 (trunk): compile.c: optimize method chain

nobu	2015-10-23 11:58:22 +0900 (Fri, 23 Oct 2015)

  New Revision: 52237

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

  Log:
    compile.c: optimize method chain
    
    * compile.c (iseq_peephole_optimize): optimize lengthy safe
      navigation method chain.  [Feature #11537]

  Modified files:
    trunk/ChangeLog
    trunk/compile.c
    trunk/test/ruby/test_iseq.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52236)
+++ ChangeLog	(revision 52237)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Oct 23 11:58:21 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* compile.c (iseq_peephole_optimize): optimize lengthy safe
+	  navigation method chain.  [Feature #11537]
+
 Fri Oct 23 10:58:41 2015  Shugo Maeda  <shugo@r...>
 
 	* lib/matrix/eigenvalue_decomposition.rb (tridiagonalize): fix
Index: compile.c
===================================================================
--- compile.c	(revision 52236)
+++ compile.c	(revision 52237)
@@ -1967,33 +1967,36 @@ iseq_peephole_optimize(rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/compile.c#L1967
 	 *   if L2
 	 */
 	INSN *nobj = (INSN *)get_destination_insn(iobj);
-	if (nobj->insn_id == BIN(jump)) {
-	    OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
-	}
+	INSN *pobj = (INSN *)iobj->link.prev;
+	int prev_dup = (pobj && pobj->insn_id == BIN(dup));
 
-	if (nobj->insn_id == BIN(dup)) {
-	    /*
-	     *   dup
-	     *   if L1
-	     *   ...
-	     * L1:
-	     *   dup
-	     *   if L2
-	     * =>
-	     *   dup
-	     *   if L2
-	     *   ...
-	     * L1:
-	     *   dup
-	     *   if L2
-	     */
-	    INSN *pobj = (INSN *)iobj->link.prev;
-	    nobj = (INSN *)nobj->link.next;
-	    /* basic blocks, with no labels in the middle */
-	    if ((pobj && pobj->insn_id == BIN(dup)) &&
-		(nobj && nobj->insn_id == iobj->insn_id)) {
+	for (;;) {
+	    if (nobj->insn_id == BIN(jump)) {
+		OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
+	    }
+	    else if (prev_dup && nobj->insn_id == BIN(dup) &&
+		     !!(nobj = (INSN *)nobj->link.next) &&
+		     /* basic blocks, with no labels in the middle */
+		     nobj->insn_id == iobj->insn_id) {
+		/*
+		 *   dup
+		 *   if L1
+		 *   ...
+		 * L1:
+		 *   dup
+		 *   if L2
+		 * =>
+		 *   dup
+		 *   if L2
+		 *   ...
+		 * L1:
+		 *   dup
+		 *   if L2
+		 */
 		OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
 	    }
+	    else break;
+	    nobj = (INSN *)get_destination_insn(nobj);
 	}
     }
 
Index: test/ruby/test_iseq.rb
===================================================================
--- test/ruby/test_iseq.rb	(revision 52236)
+++ test/ruby/test_iseq.rb	(revision 52237)
@@ -8,8 +8,12 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L8
     assert_normal_exit('p RubyVM::InstructionSequence.compile("1", "mac", "", 0).to_a', bug5894)
   end
 
+  def compile(src, line = nil, opt = nil)
+    RubyVM::InstructionSequence.new(src, __FILE__, __FILE__, line, opt)
+  end
+
   def lines src
-    body = RubyVM::InstructionSequence.new(src).to_a[13]
+    body = compile(src).to_a[13]
     body.find_all{|e| e.kind_of? Fixnum}
   end
 
@@ -52,7 +56,7 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L56
   end if defined?(RubyVM::InstructionSequence.load)
 
   def test_loaded_cdhash_mark
-    iseq = RubyVM::InstructionSequence.compile(<<-'end;', __FILE__, __FILE__, __LINE__+1)
+    iseq = compile(<<-'end;', __LINE__+1)
       def bug(kw)
         case kw
         when "false" then false
@@ -73,11 +77,11 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L77
 
   def test_disasm_encoding
     src = "\u{3042} = 1; \u{3042}; \u{3043}"
-    asm = RubyVM::InstructionSequence.compile(src).disasm
+    asm = compile(src).disasm
     assert_equal(src.encoding, asm.encoding)
     assert_predicate(asm, :valid_encoding?)
     src.encode!(Encoding::Shift_JIS)
-    asm = RubyVM::InstructionSequence.compile(src).disasm
+    asm = compile(src).disasm
     assert_equal(src.encoding, asm.encoding)
     assert_predicate(asm, :valid_encoding?)
   end
@@ -147,7 +151,7 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L151
 
   def test_disable_opt
     src = "a['foo'] = a['bar']; 'a'.freeze"
-    _,_,_,_,_,_,_,_,_,_,_,_,_,body= RubyVM::InstructionSequence.compile(src, __FILE__, __FILE__, __LINE__, false).to_a
+    body= compile(src, __LINE__, false).to_a[13]
     body.each{|insn|
       next unless Array === insn
       op = insn.first
@@ -168,11 +172,18 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L172
     code = <<-'EOS'
     ['foo', 'foo', "#{$f}foo", "#{'foo'}"]
     EOS
-    s1, s2, s3, s4 = RubyVM::InstructionSequence.compile(code, __FILE__, __FILE__, line, {frozen_string_literal: true}).eval
+    s1, s2, s3, s4 = compile(code, line, {frozen_string_literal: true}).eval
     assert_predicate(s1, :frozen?)
     assert_predicate(s2, :frozen?)
     assert_not_predicate(s3, :frozen?)
     assert_predicate(s4, :frozen?)
     assert_same(s1, s2)
   end
+
+  def test_safe_call_chain
+    src = "a.?a.?a.?a.?a.?a"
+    body = compile(src, __LINE__, {peephole_optimization: true}).to_a[13]
+    labels = body.select {|op, arg| op == :branchnil}.map {|op, arg| arg}
+    assert_equal(1, labels.uniq.size)
+  end
 end

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

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