Skip to content

Commit 956f8d4

Browse files
authored
ZJIT: Avoid redundant SP save in codegen (ruby#15448)
1 parent 66b2cc3 commit 956f8d4

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

zjit/src/codegen.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ fn gen_ccall_with_frame(
790790

791791
// Can't use gen_prepare_non_leaf_call() because we need to adjust the SP
792792
// to account for the receiver and arguments (and block arguments if any)
793-
gen_prepare_call_with_gc(asm, state, false);
793+
gen_save_pc_for_gc(asm, state);
794794
gen_save_sp(asm, caller_stack_size);
795795
gen_spill_stack(jit, asm, state);
796796
gen_spill_locals(jit, asm, state);
@@ -875,7 +875,7 @@ fn gen_ccall_variadic(
875875

876876
// Can't use gen_prepare_non_leaf_call() because we need to adjust the SP
877877
// to account for the receiver and arguments (like gen_ccall_with_frame does)
878-
gen_prepare_call_with_gc(asm, state, false);
878+
gen_save_pc_for_gc(asm, state);
879879
gen_save_sp(asm, caller_stack_size);
880880
gen_spill_stack(jit, asm, state);
881881
gen_spill_locals(jit, asm, state);
@@ -1304,8 +1304,8 @@ fn gen_send_without_block_direct(
13041304
gen_stack_overflow_check(jit, asm, state, stack_growth);
13051305

13061306
// Save cfp->pc and cfp->sp for the caller frame
1307-
gen_prepare_call_with_gc(asm, state, false);
1308-
// Special SP math. Can't use gen_prepare_non_leaf_call
1307+
// Can't use gen_prepare_non_leaf_call because we need special SP math.
1308+
gen_save_pc_for_gc(asm, state);
13091309
gen_save_sp(asm, state.stack().len() - args.len() - 1); // -1 for receiver
13101310

13111311
gen_spill_locals(jit, asm, state);
@@ -2008,6 +2008,18 @@ fn gen_incr_send_fallback_counter(asm: &mut Assembler, reason: SendFallbackReaso
20082008
}
20092009
}
20102010

2011+
/// Save only the PC to CFP. Use this when you need to call gen_save_sp()
2012+
/// immediately after with a custom stack size (e.g., gen_ccall_with_frame
2013+
/// adjusts SP to exclude receiver and arguments).
2014+
fn gen_save_pc_for_gc(asm: &mut Assembler, state: &FrameState) {
2015+
let opcode: usize = state.get_opcode().try_into().unwrap();
2016+
let next_pc: *const VALUE = unsafe { state.pc.offset(insn_len(opcode) as isize) };
2017+
2018+
gen_incr_counter(asm, Counter::vm_write_pc_count);
2019+
asm_comment!(asm, "save PC to CFP");
2020+
asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::const_ptr(next_pc));
2021+
}
2022+
20112023
/// Save the current PC on the CFP as a preparation for calling a C function
20122024
/// that may allocate objects and trigger GC. Use gen_prepare_non_leaf_call()
20132025
/// if it may raise exceptions or call arbitrary methods.
@@ -2017,13 +2029,7 @@ fn gen_incr_send_fallback_counter(asm: &mut Assembler, reason: SendFallbackReaso
20172029
/// However, to avoid marking uninitialized stack slots, this also updates SP,
20182030
/// which may have cfp->sp for a past frame or a past non-leaf call.
20192031
fn gen_prepare_call_with_gc(asm: &mut Assembler, state: &FrameState, leaf: bool) {
2020-
let opcode: usize = state.get_opcode().try_into().unwrap();
2021-
let next_pc: *const VALUE = unsafe { state.pc.offset(insn_len(opcode) as isize) };
2022-
2023-
gen_incr_counter(asm, Counter::vm_write_pc_count);
2024-
asm_comment!(asm, "save PC to CFP");
2025-
asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::const_ptr(next_pc));
2026-
2032+
gen_save_pc_for_gc(asm, state);
20272033
gen_save_sp(asm, state.stack_size());
20282034
if leaf {
20292035
asm.expect_leaf_ccall(state.stack_size());

0 commit comments

Comments
 (0)