diff options
author | Jeremy Evans <code@jeremyevans.net> | 2021-11-18 15:10:20 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-18 15:10:20 -0800 |
commit | b08dacfea39ad8da3f1fd7fdd0e4538cc892ec44 (patch) | |
tree | 0e3ab7e2f068ce840aaa4e3cbb46e2561a7c153e /test | |
parent | 4adb012926f8bd6011168327d8832cf19976de40 (diff) |
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/5002
Merged-By: jeremyevans <code@jeremyevans.net>
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_jit.rb | 8 | ||||
-rw-r--r-- | test/ruby/test_optimization.rb | 30 | ||||
-rw-r--r-- | test/ruby/test_yjit.rb | 8 |
3 files changed, 38 insertions, 8 deletions
diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb index f7ea67c023..dcbe694d7a 100644 --- a/test/ruby/test_jit.rb +++ b/test/ruby/test_jit.rb @@ -243,8 +243,8 @@ class TestJIT < Test::Unit::TestCase end; end - def test_compile_insn_putstring_concatstrings_tostring - assert_compile_once('"a#{}b" + "c"', result_inspect: '"abc"', insns: %i[putstring concatstrings tostring]) + def test_compile_insn_putstring_concatstrings_objtostring + assert_compile_once('"a#{}b" + "c"', result_inspect: '"abc"', insns: %i[putstring concatstrings objtostring]) end def test_compile_insn_toregexp @@ -482,8 +482,8 @@ class TestJIT < Test::Unit::TestCase end; end - def test_compile_insn_checktype - assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: '"42"', insns: %i[checktype]) + def test_compile_insn_objtostring + assert_compile_once("#{<<~"begin;"}\n#{<<~'end;'}", result_inspect: '"42"', insns: %i[objtostring]) begin; a = '2' "4#{a}" diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index cbae6d5e8c..a834996788 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -903,4 +903,34 @@ class TestRubyOptimization < Test::Unit::TestCase raise "END" end; end + + class Objtostring + end + + def test_objtostring + assert_raise(NoMethodError){"#{BasicObject.new}"} + assert_redefine_method('Symbol', 'to_s', <<-'end') + assert_match %r{\A#<Symbol:0x[0-9a-f]+>\z}, "#{:foo}" + end + assert_redefine_method('NilClass', 'to_s', <<-'end') + assert_match %r{\A#<NilClass:0x[0-9a-f]+>\z}, "#{nil}" + end + assert_redefine_method('TrueClass', 'to_s', <<-'end') + assert_match %r{\A#<TrueClass:0x[0-9a-f]+>\z}, "#{true}" + end + assert_redefine_method('FalseClass', 'to_s', <<-'end') + assert_match %r{\A#<FalseClass:0x[0-9a-f]+>\z}, "#{false}" + end + assert_redefine_method('Integer', 'to_s', <<-'end') + (-1..10).each { |i| + assert_match %r{\A#<Integer:0x[0-9a-f]+>\z}, "#{i}" + } + end + assert_equal "TestRubyOptimization::Objtostring", "#{Objtostring}" + assert_match %r{\A#<Class:0x[0-9a-f]+>\z}, "#{Class.new}" + assert_match %r{\A#<Module:0x[0-9a-f]+>\z}, "#{Module.new}" + o = Object.new + def o.to_s; 1; end + assert_match %r{\A#<Object:0x[0-9a-f]+>\z}, "#{o}" + end end diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index f0d899e908..9cb727eae1 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -215,7 +215,7 @@ class TestYJIT < Test::Unit::TestCase def test_compile_tostring assert_no_exits('"i am a string #{true}"') - end + end if false # Until objtostring supported def test_compile_opt_aset assert_compiles('[1,2,3][2] = 4', insns: %i[opt_aset]) @@ -240,7 +240,7 @@ class TestYJIT < Test::Unit::TestCase def test_compile_regexp assert_no_exits('/#{true}/') - end + end if false # Until objtostring supported def test_getlocal_with_level assert_compiles(<<~RUBY, insns: %i[getlocal opt_plus], result: [[7]]) @@ -385,7 +385,7 @@ class TestYJIT < Test::Unit::TestCase make_str("foo", "bar") make_str("foo", "bar") RUBY - end + end if false # Until objtostring supported def test_string_interpolation_cast assert_compiles(<<~'RUBY', insns: %i[checktype concatstrings tostring], result: "123") @@ -395,7 +395,7 @@ class TestYJIT < Test::Unit::TestCase make_str(1, 23) RUBY - end + end if false # Until objtostring supported def test_checkkeyword assert_compiles(<<~'RUBY', insns: %i[checkkeyword], result: [2, 5]) |