summaryrefslogtreecommitdiff
diff options
authorTakashi Kokubun <[email protected]>2025-07-14 12:22:13 -0700
committerGitHub <[email protected]>2025-07-14 12:22:13 -0700
commite288a86692694351278d0c3973881017b5b2e9c6 (patch)
tree2e23f90f5119d0c2740494a517faf15a7175afc0
parentb2a7b7699261d2a4ef8a9d5d38d3fb9dc99c8253 (diff)
ZJIT: Restore SP register after JIT-to-JIT call (#13882)HEADmaster
Co-authored-by: Alan Wu <[email protected]> Co-authored-by: Stan Lo <[email protected]>
-rw-r--r--test/ruby/test_zjit.rb14
-rw-r--r--zjit/src/codegen.rs8
2 files changed, 21 insertions, 1 deletions
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
index a54d965872..f71509bc7c 100644
--- a/test/ruby/test_zjit.rb
+++ b/test/ruby/test_zjit.rb
@@ -905,6 +905,20 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 2, insns: [:defined]
end
+ def test_invokeblock_without_block_after_jit_call
+ assert_compiles '"no block given (yield)"', %q{
+ def test(*arr, &b)
+ arr.class
+ yield
+ end
+ begin
+ test
+ rescue => e
+ e.message
+ end
+ }
+ end
+
def test_putspecialobject_vm_core_and_cbase
assert_compiles '10', %q{
def test
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index cea2da54ef..79460ccdfb 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -757,7 +757,8 @@ fn gen_send_without_block_direct(
asm_comment!(asm, "switch to new SP register");
let local_size = unsafe { get_iseq_body_local_table_size(iseq) } as usize;
- let new_sp = asm.add(SP, ((state.stack().len() + local_size - args.len() + VM_ENV_DATA_SIZE as usize) * SIZEOF_VALUE).into());
+ let sp_offset = (state.stack().len() + local_size - args.len() + VM_ENV_DATA_SIZE as usize) * SIZEOF_VALUE;
+ let new_sp = asm.add(SP, sp_offset.into());
asm.mov(SP, new_sp);
asm_comment!(asm, "switch to new CFP");
@@ -780,9 +781,14 @@ fn gen_send_without_block_direct(
// If a callee side-exits, i.e. returns Qundef, propagate the return value to the caller.
// The caller will side-exit the callee into the interpreter.
// TODO: Let side exit code pop all JIT frames to optimize away this cmp + je.
+ asm_comment!(asm, "side-exit if callee side-exits");
asm.cmp(ret, Qundef.into());
asm.je(ZJITState::get_exit_trampoline().into());
+ asm_comment!(asm, "restore SP register for the caller");
+ let new_sp = asm.sub(SP, sp_offset.into());
+ asm.mov(SP, new_sp);
+
Some(ret)
}
close