diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb index c195bbdc53..481e1754bf 100644 --- a/test/ruby/test_jit.rb +++ b/test/ruby/test_jit.rb @@ -419,11 +419,40 @@ class TestJIT < Test::Unit::TestCase assert_compile_once('[1] << 2', result_inspect: '[1, 2]') end - def test_compile_insn_opt_aref_aset - assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '8') + def test_compile_insn_opt_aref + # optimized call (optimized JIT) -> send call + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '21', success_count: 2, min_calls: 1) + begin; + obj = Object.new + def obj.[](h) + h + end + + block = proc { |h| h[1] } + print block.call({ 1 => 2 }) + print block.call(obj) + end; + + # send call -> optimized call (send JIT) -> optimized call + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '122', success_count: 1, min_calls: 2) + begin; + obj = Object.new + def obj.[](h) + h + end + + block = proc { |h| h[1] } + print block.call(obj) + print block.call({ 1 => 2 }) + print block.call({ 1 => 2 }) + end; + end + + def test_compile_insn_opt_aset + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '5') begin; hash = { '1' => 2 } - hash['1'] + hash[1.to_s] + (hash['2'] = 2) + (hash[2.to_s] = 2) + (hash['2'] = 2) + (hash[1.to_s] = 3) end; end @@ -479,8 +508,8 @@ class TestJIT < Test::Unit::TestCase end # Shorthand for normal test cases - def assert_eval_with_jit(script, stdout: nil, success_count:) - out, err = eval_with_jit(script, verbose: 1, min_calls: 1) + def assert_eval_with_jit(script, stdout: nil, success_count:, min_calls: 1) + out, err = eval_with_jit(script, verbose: 1, min_calls: min_calls) actual = err.scan(/^#{JIT_SUCCESS_PREFIX}:/).size assert_equal( success_count, actual, diff --git a/tool/ruby_vm/views/mjit_compile.inc.erb b/tool/ruby_vm/views/mjit_compile.inc.erb index 3c4dba6786..a23537e4bc 100644 --- a/tool/ruby_vm/views/mjit_compile.inc.erb +++ b/tool/ruby_vm/views/mjit_compile.inc.erb @@ -21,6 +21,11 @@ % 'opt_call_c_function', # low priority % ] % +% opt_send_without_block = RubyVM::Instructions.find { |i| i.name == 'opt_send_without_block' } +% if opt_send_without_block.nil? +% raise 'opt_send_without_block not found' +% end +% % # Available variables and macros in JIT-ed function: % # ec: the first argument of _mjitXXX % # reg_cfp: the second argument of _mjitXXX @@ -46,6 +51,8 @@ switch (insn) { case BIN(<%= insn.name %>): % if %w[opt_send_without_block send].include?(insn.name) <%= render 'mjit_compile_send', locals: { insn: insn } -%> +% elsif %w[opt_aref].include?(insn.name) # experimental. TODO: increase insns and make the list automatically by finding DISPATCH_ORIGINAL_INSN +<%= render 'mjit_compile_send', locals: { insn: opt_send_without_block } -%> % end <%= render 'mjit_compile_insn', locals: { insn: insn, dispatched: false } -%> break;