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

ruby-changes:42641

From: nagachika <ko1@a...>
Date: Sat, 23 Apr 2016 00:02:57 +0900 (JST)
Subject: [ruby-changes:42641] nagachika:r54715 (ruby_2_3): merge revision(s) 54141, 54542, 54548: [Backport #12082]

nagachika	2016-04-23 00:59:34 +0900 (Sat, 23 Apr 2016)

  New Revision: 54715

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

  Log:
    merge revision(s) 54141,54542,54548: [Backport #12082]
    
    test_optimization.rb: tailcall
    
    * test/ruby/test_optimization.rb (TestRubyOptimization.tailcall):
      helper method to compile methods with tailcall optimization
      enabled.
    * compile.c (iseq_optimize): disable tail call optimization in
      rescued, rescue, and ensure blocks.
      [ruby-core:73871] [Bug #12082]
    
    * compile.c (new_label_body): initialize bit fields, since
      compile_data_alloc does not clear the memory.  [Bug #12082]

  Modified directories:
    branches/ruby_2_3/
  Modified files:
    branches/ruby_2_3/ChangeLog
    branches/ruby_2_3/compile.c
    branches/ruby_2_3/test/ruby/test_optimization.rb
    branches/ruby_2_3/version.h
Index: ruby_2_3/compile.c
===================================================================
--- ruby_2_3/compile.c	(revision 54714)
+++ ruby_2_3/compile.c	(revision 54715)
@@ -47,6 +47,13 @@ typedef struct iseq_link_anchor { https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L47
     LINK_ELEMENT *last;
 } LINK_ANCHOR;
 
+typedef enum {
+    LABEL_RESCUE_NONE,
+    LABEL_RESCUE_BEG,
+    LABEL_RESCUE_END,
+    LABEL_RESCUE_TYPE_MAX
+} LABEL_RESCUE_TYPE;
+
 typedef struct iseq_label_data {
     LINK_ELEMENT link;
     int label_no;
@@ -55,6 +62,7 @@ typedef struct iseq_label_data { https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L62
     int set;
     int sp;
     int refcnt;
+    unsigned int rescued: 2;
 } LABEL;
 
 typedef struct iseq_insn_data {
@@ -561,6 +569,9 @@ rb_iseq_compile_node(rb_iseq_t *iseq, NO https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L569
 		LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
 		LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
 
+		start->rescued = LABEL_RESCUE_BEG;
+		end->rescued = LABEL_RESCUE_END;
+
 		ADD_TRACE(ret, FIX2INT(iseq->body->location.first_lineno), RUBY_EVENT_B_CALL);
 		ADD_LABEL(ret, start);
 		COMPILE(ret, "block body", node->nd_body);
@@ -989,6 +1000,8 @@ new_label_body(rb_iseq_t *iseq, long lin https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L1000
     labelobj->sc_state = 0;
     labelobj->sp = -1;
     labelobj->refcnt = 0;
+    labelobj->set = 0;
+    labelobj->rescued = LABEL_RESCUE_NONE;
     return labelobj;
 }
 
@@ -2323,20 +2336,37 @@ iseq_specialized_instruction(rb_iseq_t * https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L2336
     return COMPILE_OK;
 }
 
+static inline int
+tailcallable_p(rb_iseq_t *iseq)
+{
+    switch (iseq->body->type) {
+      case ISEQ_TYPE_RESCUE:
+      case ISEQ_TYPE_ENSURE:
+	/* rescue block can't tail call because of errinfo */
+	return FALSE;
+      default:
+	return TRUE;
+    }
+}
+
 static int
 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
 {
     LINK_ELEMENT *list;
     const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
-    const int do_tailcallopt = ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
+    const int do_tailcallopt = tailcallable_p(iseq) &&
+	ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
     const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
     const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
+    int rescue_level = 0;
+    int tailcallopt = do_tailcallopt;
+
     list = FIRST_ELEMENT(anchor);
 
     while (list) {
 	if (list->type == ISEQ_ELEMENT_INSN) {
 	    if (do_peepholeopt) {
-		iseq_peephole_optimize(iseq, list, do_tailcallopt);
+		iseq_peephole_optimize(iseq, list, tailcallopt);
 	    }
 	    if (do_si) {
 		iseq_specialized_instruction(iseq, (INSN *)list);
@@ -2345,6 +2375,17 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCH https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L2375
 		insn_operands_unification((INSN *)list);
 	    }
 	}
+	if (list->type == ISEQ_ELEMENT_LABEL) {
+	    switch (((LABEL *)list)->rescued) {
+	      case LABEL_RESCUE_BEG:
+		rescue_level++;
+		tailcallopt = FALSE;
+		break;
+	      case LABEL_RESCUE_END:
+		if (!--rescue_level) tailcallopt = do_tailcallopt;
+		break;
+	    }
+	}
 	list = list->next;
     }
     return COMPILE_OK;
@@ -3449,6 +3490,8 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHO https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L3490
 							       ("defined guard in "),
 							       iseq->body->location.label),
 						 ISEQ_TYPE_DEFINED_GUARD, 0);
+	lstart->rescued = LABEL_RESCUE_BEG;
+	lend->rescued = LABEL_RESCUE_END;
 	APPEND_LABEL(ret, lcur, lstart);
 	ADD_LABEL(ret, lend);
 	ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
@@ -4246,6 +4289,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/ruby_2_3/compile.c#L4289
 						 rb_str_concat(rb_str_new2("rescue in "), iseq->body->location.label),
 						 ISEQ_TYPE_RESCUE, line);
 
+	lstart->rescued = LABEL_RESCUE_BEG;
+	lend->rescued = LABEL_RESCUE_END;
 	ADD_LABEL(ret, lstart);
 	COMPILE(ret, "rescue head", node->nd_head);
 	ADD_LABEL(ret, lend);
Index: ruby_2_3/test/ruby/test_optimization.rb
===================================================================
--- ruby_2_3/test/ruby/test_optimization.rb	(revision 54714)
+++ ruby_2_3/test/ruby/test_optimization.rb	(revision 54715)
@@ -230,47 +230,54 @@ class TestRubyOptimization < Test::Unit: https://github.com/ruby/ruby/blob/trunk/ruby_2_3/test/ruby/test_optimization.rb#L230
     assert_equal true, MyObj.new == nil
   end
 
+  def self.tailcall(klass, src, file = nil, path = nil, line = nil)
+    unless file
+      loc, = caller_locations(1, 1)
+      file = loc.path
+      line ||= loc.lineno
+    end
+    RubyVM::InstructionSequence.new("proc {|_|_.class_eval {#{src}}}",
+                                    file, (path || file), line,
+                                    tailcall_optimization: true,
+                                    trace_instruction: false)
+      .eval[klass]
+  end
+
+  def tailcall(*args)
+    self.class.tailcall(singleton_class, *args)
+  end
+
   def test_tailcall
     bug4082 = '[ruby-core:33289]'
 
-    option = {
-      tailcall_optimization: true,
-      trace_instruction: false,
-    }
-    RubyVM::InstructionSequence.new(<<-EOF, "Bug#4082", bug4082, nil, option).eval
-      class #{self.class}::Tailcall
-        def fact_helper(n, res)
-          if n == 1
-            res
-          else
-            fact_helper(n - 1, n * res)
-          end
-        end
-        def fact(n)
-          fact_helper(n, 1)
+    tailcall(<<-EOF)
+      def fact_helper(n, res)
+        if n == 1
+          res
+        else
+          fact_helper(n - 1, n * res)
         end
       end
+      def fact(n)
+        fact_helper(n, 1)
+      end
     EOF
-    assert_equal(9131, Tailcall.new.fact(3000).to_s.size, bug4082)
+    assert_equal(9131, fact(3000).to_s.size, bug4082)
   end
 
   def test_tailcall_with_block
     bug6901 = '[ruby-dev:46065]'
 
-    option = {
-      tailcall_optimization: true,
-      trace_instruction: false,
-    }
-    RubyVM::InstructionSequence.new(<<-EOF, "Bug#6901", bug6901, nil, option).eval
-  def identity(val)
-    val
-  end
+    tailcall(<<-EOF)
+      def identity(val)
+        val
+      end
 
-  def delay
-    -> {
-      identity(yield)
-    }
-  end
+      def delay
+        -> {
+          identity(yield)
+        }
+      end
     EOF
     assert_equal(123, delay { 123 }.call, bug6901)
   end
@@ -280,15 +287,36 @@ class TestRubyOptimization < Test::Unit: https://github.com/ruby/ruby/blob/trunk/ruby_2_3/test/ruby/test_optimization.rb#L287
   end
 
   def test_tailcall_inhibited_by_block
-    assert_separately([], <<~'end;')
-      def just_yield
-        yield
-      end
-      iseq = RubyVM::InstructionSequence
-      result = iseq.compile("just_yield {:ok}", __FILE__, __FILE__, __LINE__,
-                            tailcall_optimization: true).eval
-      assert_equal(:ok, result)
+    tailcall(<<-EOF)
+      def yield_result
+        just_yield {:ok}
+      end
+    EOF
+    assert_equal(:ok, yield_result)
+  end
+
+  def do_raise
+    raise "should be rescued"
+  end
+
+  def errinfo
+    $!
+  end
+
+  def test_tailcall_inhibited_by_rescue
+    bug12082 = '[ruby-core:73871] [Bug #12082]'
+
+    tailcall(<<-'end;')
+      def to_be_rescued
+        return do_raise
+        1 + 2
+      rescue
+        errinfo
+      end
     end;
+    result = to_be_rescued
+    assert_instance_of(RuntimeError, result, bug12082)
+    assert_equal("should be rescued", result.message, bug12082)
   end
 
   class Bug10557
Index: ruby_2_3/version.h
===================================================================
--- ruby_2_3/version.h	(revision 54714)
+++ ruby_2_3/version.h	(revision 54715)
@@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_3/version.h#L1
 #define RUBY_VERSION "2.3.0"
 #define RUBY_RELEASE_DATE "2016-04-23"
-#define RUBY_PATCHLEVEL 104
+#define RUBY_PATCHLEVEL 105
 
 #define RUBY_RELEASE_YEAR 2016
 #define RUBY_RELEASE_MONTH 4
Index: ruby_2_3/ChangeLog
===================================================================
--- ruby_2_3/ChangeLog	(revision 54714)
+++ ruby_2_3/ChangeLog	(revision 54715)
@@ -1,3 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_3/ChangeLog#L1
+Sat Apr 23 00:51:51 2016  Nobuyoshi Nakada  <nobu@r...>
+
+	* compile.c (new_label_body): initialize bit fields, since
+	  compile_data_alloc does not clear the memory.  [Bug #12082]
+
+Sat Apr 23 00:51:51 2016  Nobuyoshi Nakada  <nobu@r...>
+
+	* compile.c (iseq_optimize): disable tail call optimization in
+	  rescued, rescue, and ensure blocks.
+	  [ruby-core:73871] [Bug #12082]
+
 Sat Apr 23 00:33:04 2016  NARUSE, Yui  <naruse@r...>
 
 	* ext/nkf/nkf-utf8/nkf.c (mime_putc): fix typo.

Property changes on: ruby_2_3
___________________________________________________________________
Modified: svn:mergeinfo
   Merged /trunk:r54141,54542,54548


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

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