summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-11-11 15:35:29 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-11-11 15:35:29 +0000
commitc5ee9b38687b66833081cb58f042b21c586a0142 (patch)
tree5f44ca3583ae4e97bdea70383d5db59818120acd
parenta6f510959e409cb32e8da6a0b6417ac6325302eb (diff)
merge revision(s) 56208,56663: [Backport #12905]
* compile.c (iseq_peephole_optimize): enable tail call optimization inside a conditional block. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_3@56715 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--compile.c7
-rw-r--r--test/ruby/test_optimization.rb33
-rw-r--r--version.h2
4 files changed, 44 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index d541062461..fe1ad58f6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Sat Nov 12 00:27:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_peephole_optimize): enable tail call
+ optimization inside a conditional block.
+
Sat Nov 5 11:53:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* io.c (copy_stream_body): use IO to write to copy to duplex IO.
diff --git a/compile.c b/compile.c
index 1c29a721ac..f767dc4b05 100644
--- a/compile.c
+++ b/compile.c
@@ -2240,6 +2240,13 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
/*case BIN(trace):*/
next = next->next;
break;
+ case BIN(jump):
+ /* if cond
+ * return tailcall
+ * end
+ */
+ next = get_destination_insn((INSN *)next);
+ break;
case BIN(leave):
piobj = iobj;
default:
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index f147f9d8c6..499d4e1c7c 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -230,7 +230,7 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_equal true, MyObj.new == nil
end
- def self.tailcall(klass, src, file = nil, path = nil, line = nil)
+ def self.tailcall(klass, src, file = nil, path = nil, line = nil, tailcall: true)
unless file
loc, = caller_locations(1, 1)
file = loc.path
@@ -238,7 +238,7 @@ class TestRubyOptimization < Test::Unit::TestCase
end
RubyVM::InstructionSequence.new("proc {|_|_.class_eval {#{src}}}",
file, (path || file), line,
- tailcall_optimization: true,
+ tailcall_optimization: tailcall,
trace_instruction: false)
.eval[klass]
end
@@ -334,6 +334,35 @@ class TestRubyOptimization < Test::Unit::TestCase
message(bug12565) {disasm(:add_one_and_two)})
end
+ def test_tailcall_condition_block
+ bug = '[ruby-core:78015] [Bug #12905]'
+
+ src = "#{<<-"begin;"}\n#{<<-"end;"}"
+ begin;
+ def run(current, final)
+ if current < final
+ run(current+1, final)
+ else
+ nil
+ end
+ end
+ end;
+
+ obj = Object.new
+ self.class.tailcall(obj.singleton_class, src, tailcall: false)
+ e = assert_raise(SystemStackError) {
+ obj.run(1, Float::INFINITY)
+ }
+ level = e.backtrace_locations.size
+ obj = Object.new
+ self.class.tailcall(obj.singleton_class, src, tailcall: true)
+ level *= 2
+ mesg = message {"#{bug}: #{$!.backtrace_locations.size} / #{level} stack levels"}
+ assert_nothing_raised(SystemStackError, mesg) {
+ obj.run(1, level)
+ }
+ end
+
class Bug10557
def [](_)
block_given?
diff --git a/version.h b/version.h
index 437e3eddbb..c6fdb2f18e 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.3.2"
#define RUBY_RELEASE_DATE "2016-11-12"
-#define RUBY_PATCHLEVEL 206
+#define RUBY_PATCHLEVEL 207
#define RUBY_RELEASE_YEAR 2016
#define RUBY_RELEASE_MONTH 11