_mjit_compile_send.erb: inline recursive call

mjit_compile.c: propagate funcname to compile_insn

test_jit.rb: add test covering this behavior

* Benchmark

```
require 'benchmark_driver'

Benchmark.driver(runner: :time, repeat_count: 4) do |x|
  x.prelude %{
    def fib(x)
      return x if x == 0 || x == 1
      fib(x-1) + fib(x-2)
    end
  }
  x.report 'fib(40)'
  x.loop_count 1

  x.rbenv(
    'before,--jit',
    'before',
    'after,--jit',
    'after',
  )
  x.verbose
end
```

```
before,--jit: ruby 2.6.0dev (2018-05-08 trunk 63349) +JIT [x86_64-linux]
before: ruby 2.6.0dev (2018-05-08 trunk 63349) [x86_64-linux]
after,--jit: ruby 2.6.0dev (2018-05-08 trunk 63349) +JIT [x86_64-linux]
last_commit=_mjit_compile_send.erb: inline recursive call
after: ruby 2.6.0dev (2018-05-08 trunk 63349) [x86_64-linux]
last_commit=_mjit_compile_send.erb: inline recursive call
Calculating -------------------------------------
                     before,--jit      before  after,--jit       after
             fib(40)        2.886       8.685        2.562       8.800 s -       1.000 times

Comparison:
                          fib(40)
         after,--jit:         2.6 s
        before,--jit:         2.9 s - 1.13x  slower
              before:         8.7 s - 3.39x  slower
               after:         8.8 s - 3.44x  slower

```

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63350 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
k0kubun 2018-05-07 16:16:59 +00:00
Родитель a4a66510fb
Коммит 6c62356e5a
3 изменённых файлов: 15 добавлений и 0 удалений

Просмотреть файл

@ -27,6 +27,7 @@ struct compile_status {
/* If TRUE, JIT-ed code will use local variables to store pushed values instead of
using VM's stack and moving stack pointer. */
int local_stack_p;
const char *funcname; /* the method name which is being compiled */
};
/* Storage to keep data which is consistent in each conditional branch.
@ -193,6 +194,7 @@ mjit_compile(FILE *f, const struct rb_iseq_constant_body *body, const char *func
status.success = TRUE;
status.local_stack_p = !body->catch_except_p;
status.stack_size_for_pos = ALLOC_N(int, body->iseq_size);
status.funcname = funcname;
memset(status.stack_size_for_pos, NOT_COMPILED_STACK_SIZE, sizeof(int) * body->iseq_size);
/* For performance, we verify stack size only on compilation time (mjit_compile.inc.erb) without --jit-debug */

Просмотреть файл

@ -322,6 +322,16 @@ class TestJIT < Test::Unit::TestCase
def test_compile_insn_opt_send_without_block
assert_compile_once('print', result_inspect: 'nil', insns: %i[opt_send_without_block])
# recursive inline
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '120', success_count: 1, min_calls: 2)
begin;
def fact(i)
return i if i <= 1
i * fact(i - 1)
end
print fact(5)
end;
end
def test_compile_insn_invokesuper

Просмотреть файл

@ -58,6 +58,9 @@
fprintf(f, " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n");
fprintf(f, " v = vm_exec(ec, TRUE);\n");
}
else if (body == iseq->body) { /* inline recursive call */
fprintf(f, " v = %s(ec, ec->cfp);\n", status->funcname);
}
else {
fprintf(f, " if ((v = mjit_exec(ec)) == Qundef) {\n");
fprintf(f, " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n"); /* This is vm_call0_body's code after vm_call_iseq_setup */