diff options
| -rw-r--r-- | benchmark/mjit_leave.yml | 7 | ||||
| -rw-r--r-- | tool/ruby_vm/views/mjit_compile.inc.erb | 20 |
2 files changed, 22 insertions, 5 deletions
diff --git a/benchmark/mjit_leave.yml b/benchmark/mjit_leave.yml new file mode 100644 index 0000000000..292d6ef041 --- /dev/null +++ b/benchmark/mjit_leave.yml @@ -0,0 +1,7 @@ +prelude: | + def leave + nil + end +benchmark: + mjit_leave: leave +loop_count: 200000000 diff --git a/tool/ruby_vm/views/mjit_compile.inc.erb b/tool/ruby_vm/views/mjit_compile.inc.erb index b51e777cb8..500a4fcf2c 100644 --- a/tool/ruby_vm/views/mjit_compile.inc.erb +++ b/tool/ruby_vm/views/mjit_compile.inc.erb @@ -70,12 +70,22 @@ switch (insn) { fprintf(stderr, "MJIT warning: Unexpected JIT stack_size on leave: %d\n", b->stack_size); status->success = false; } -% # Special leave for an inlined call. - if (status->inlined_iseqs == NULL) { // the current ISeq is being inlined - fprintf(f, " return stack[0];\n"); - b->stack_size += <%= insn.call_attribute('sp_inc') %>; - break; +% # Skip vm_pop_frame for inlined call + if (status->inlined_iseqs != NULL) { // the current ISeq is NOT being inlined +% # Cancel on interrupts to make leave insn leaf + fprintf(f, " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n"); + if (status->local_stack_p) { + fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size); + } + fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", pos); + fprintf(f, " goto cancel;\n"); + fprintf(f, " }\n"); + fprintf(f, " ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(reg_cfp);\n"); // vm_pop_frame } + fprintf(f, " return stack[0];\n"); + b->stack_size += <%= insn.call_attribute('sp_inc') %>; + b->finish_p = TRUE; + break; % end % % # Main insn implementation generated by insns.def |
