Skip to content

Commit 388cfee

Browse files
committed
ZJIT: Restore SP on side-exit chains
1 parent a6aac06 commit 388cfee

File tree

3 files changed

+51
-33
lines changed

3 files changed

+51
-33
lines changed

zjit/src/backend/lir.rs

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,14 @@ impl From<VALUE> for Opnd {
270270
}
271271
}
272272

273+
/// Set of things we need to restore for side exits.
274+
#[derive(Clone, Debug)]
275+
pub struct SideExitContext {
276+
pub pc: *const VALUE,
277+
pub stack: Vec<Opnd>,
278+
pub locals: Vec<Opnd>,
279+
}
280+
273281
/// Branch target (something that we can jump to)
274282
/// for branch instructions
275283
#[derive(Clone, Debug)]
@@ -281,12 +289,14 @@ pub enum Target
281289
Label(Label),
282290
/// Side exit to the interpreter
283291
SideExit {
284-
pc: *const VALUE,
285-
stack: Vec<Opnd>,
286-
locals: Vec<Opnd>,
287-
c_stack_bytes: usize,
292+
/// Context to restore on regular side exits. None for side exits right
293+
/// after JIT-to-JIT calls because we restore them before the JIT call.
294+
context: Option<SideExitContext>,
295+
/// We use this to enrich asm comments.
288296
reason: SideExitReason,
289-
// Some if the side exit should write this label. We use it for patch points.
297+
/// The number of bytes we need to adjust the C stack pointer by.
298+
c_stack_bytes: usize,
299+
/// Some if the side exit should write this label. We use it for patch points.
290300
label: Option<Label>,
291301
},
292302
}
@@ -767,7 +777,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
767777
Insn::Label(target) |
768778
Insn::LeaJumpTarget { target, .. } |
769779
Insn::PatchPoint(target) => {
770-
if let Target::SideExit { stack, locals, .. } = target {
780+
if let Target::SideExit { context: Some(SideExitContext { stack, locals, .. }), .. } = target {
771781
let stack_idx = self.idx;
772782
if stack_idx < stack.len() {
773783
let opnd = &stack[stack_idx];
@@ -792,7 +802,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
792802
return Some(opnd);
793803
}
794804

795-
if let Target::SideExit { stack, locals, .. } = target {
805+
if let Target::SideExit { context: Some(SideExitContext { stack, locals, .. }), .. } = target {
796806
let stack_idx = self.idx - 1;
797807
if stack_idx < stack.len() {
798808
let opnd = &stack[stack_idx];
@@ -923,7 +933,7 @@ impl<'a> InsnOpndMutIterator<'a> {
923933
Insn::Label(target) |
924934
Insn::LeaJumpTarget { target, .. } |
925935
Insn::PatchPoint(target) => {
926-
if let Target::SideExit { stack, locals, .. } = target {
936+
if let Target::SideExit { context: Some(SideExitContext { stack, locals, .. }), .. } = target {
927937
let stack_idx = self.idx;
928938
if stack_idx < stack.len() {
929939
let opnd = &mut stack[stack_idx];
@@ -948,7 +958,7 @@ impl<'a> InsnOpndMutIterator<'a> {
948958
return Some(opnd);
949959
}
950960

951-
if let Target::SideExit { stack, locals, .. } = target {
961+
if let Target::SideExit { context: Some(SideExitContext { stack, locals, .. }), .. } = target {
952962
let stack_idx = self.idx - 1;
953963
if stack_idx < stack.len() {
954964
let opnd = &mut stack[stack_idx];
@@ -1803,7 +1813,7 @@ impl Assembler
18031813
for (idx, target) in targets {
18041814
// Compile a side exit. Note that this is past the split pass and alloc_regs(),
18051815
// so you can't use a VReg or an instruction that needs to be split.
1806-
if let Target::SideExit { pc, stack, locals, c_stack_bytes, reason, label } = target {
1816+
if let Target::SideExit { context, reason, c_stack_bytes, label } = target {
18071817
asm_comment!(self, "Exit: {reason}");
18081818
let side_exit_label = if let Some(label) = label {
18091819
Target::Label(label)
@@ -1823,26 +1833,30 @@ impl Assembler
18231833
}
18241834
}
18251835

1826-
asm_comment!(self, "write stack slots: {stack:?}");
1827-
for (idx, &opnd) in stack.iter().enumerate() {
1828-
let opnd = split_store_source(self, opnd);
1829-
self.store(Opnd::mem(64, SP, idx as i32 * SIZEOF_VALUE_I32), opnd);
1830-
}
1836+
// Restore the PC and the stack for regular side exits. We don't do this for
1837+
// side exits right after JIT-to-JIT calls, which restore them before the call.
1838+
if let Some(SideExitContext { pc, stack, locals }) = context {
1839+
asm_comment!(self, "write stack slots: {stack:?}");
1840+
for (idx, &opnd) in stack.iter().enumerate() {
1841+
let opnd = split_store_source(self, opnd);
1842+
self.store(Opnd::mem(64, SP, idx as i32 * SIZEOF_VALUE_I32), opnd);
1843+
}
18311844

1832-
asm_comment!(self, "write locals: {locals:?}");
1833-
for (idx, &opnd) in locals.iter().enumerate() {
1834-
let opnd = split_store_source(self, opnd);
1835-
self.store(Opnd::mem(64, SP, (-local_size_and_idx_to_ep_offset(locals.len(), idx) - 1) * SIZEOF_VALUE_I32), opnd);
1836-
}
1845+
asm_comment!(self, "write locals: {locals:?}");
1846+
for (idx, &opnd) in locals.iter().enumerate() {
1847+
let opnd = split_store_source(self, opnd);
1848+
self.store(Opnd::mem(64, SP, (-local_size_and_idx_to_ep_offset(locals.len(), idx) - 1) * SIZEOF_VALUE_I32), opnd);
1849+
}
18371850

1838-
asm_comment!(self, "save cfp->pc");
1839-
self.load_into(Opnd::Reg(Assembler::SCRATCH_REG), Opnd::const_ptr(pc));
1840-
self.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::Reg(Assembler::SCRATCH_REG));
1851+
asm_comment!(self, "save cfp->pc");
1852+
self.load_into(Opnd::Reg(Assembler::SCRATCH_REG), Opnd::const_ptr(pc));
1853+
self.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::Reg(Assembler::SCRATCH_REG));
18411854

1842-
asm_comment!(self, "save cfp->sp");
1843-
self.lea_into(Opnd::Reg(Assembler::SCRATCH_REG), Opnd::mem(64, SP, stack.len() as i32 * SIZEOF_VALUE_I32));
1844-
let cfp_sp = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP);
1845-
self.store(cfp_sp, Opnd::Reg(Assembler::SCRATCH_REG));
1855+
asm_comment!(self, "save cfp->sp");
1856+
self.lea_into(Opnd::Reg(Assembler::SCRATCH_REG), Opnd::mem(64, SP, stack.len() as i32 * SIZEOF_VALUE_I32));
1857+
let cfp_sp = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP);
1858+
self.store(cfp_sp, Opnd::Reg(Assembler::SCRATCH_REG));
1859+
}
18461860

18471861
if c_stack_bytes > 0 {
18481862
asm_comment!(self, "restore C stack pointer");

zjit/src/codegen.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::invariants::track_bop_assumption;
77
use crate::gc::get_or_create_iseq_payload;
88
use crate::state::ZJITState;
99
use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr};
10-
use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, SP};
10+
use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, SideExitContext, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, SP};
1111
use crate::hir::{iseq_to_hir, Block, BlockId, BranchEdge, CallInfo, Invariant, RangeType, SideExitReason, SideExitReason::*, SpecialObjectType, SELF_PARAM_IDX};
1212
use crate::hir::{Const, FrameState, Function, Insn, InsnId};
1313
use crate::hir_type::{types::Fixnum, Type};
@@ -774,7 +774,8 @@ fn gen_send_without_block_direct(
774774
// TODO: Let side exit code pop all JIT frames to optimize away this cmp + je.
775775
asm_comment!(asm, "side-exit if callee side-exits");
776776
asm.cmp(ret, Qundef.into());
777-
asm.je(ZJITState::get_exit_trampoline().into());
777+
// Restore the C stack pointer on exit
778+
asm.je(Target::SideExit { context: None, reason: CalleeSideExit, c_stack_bytes: jit.c_stack_bytes, label: None });
778779

779780
asm_comment!(asm, "restore SP register for the caller");
780781
let new_sp = asm.sub(SP, sp_offset.into());
@@ -1112,11 +1113,13 @@ fn build_side_exit(jit: &mut JITState, state: &FrameState, reason: SideExitReaso
11121113
}
11131114

11141115
let target = Target::SideExit {
1115-
pc: state.pc,
1116-
stack,
1117-
locals,
1118-
c_stack_bytes: jit.c_stack_bytes,
1116+
context: Some(SideExitContext {
1117+
pc: state.pc,
1118+
stack,
1119+
locals,
1120+
}),
11191121
reason,
1122+
c_stack_bytes: jit.c_stack_bytes,
11201123
label,
11211124
};
11221125
Some(target)

zjit/src/hir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ pub enum SideExitReason {
414414
GuardType(Type),
415415
GuardBitEquals(VALUE),
416416
PatchPoint(Invariant),
417+
CalleeSideExit,
417418
}
418419

419420
impl std::fmt::Display for SideExitReason {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy