aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--benchmark/mjit_leave.yml7
-rw-r--r--tool/ruby_vm/views/mjit_compile.inc.erb20
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