From d690e8327644102386deeaeee8eb4818c24fd38b Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Thu, 21 Aug 2025 16:22:26 -0400 Subject: ZJIT: Add CheckInterrupts HIR instruction --- zjit/src/codegen.rs | 12 ++++++++++++ zjit/src/hir.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 0549365666..16d44c74b0 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -395,6 +395,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::GetSpecialNumber { nth, state } => gen_getspecial_number(asm, *nth, &function.frame_state(*state)), &Insn::IncrCounter(counter) => no_output!(gen_incr_counter(asm, counter)), Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state)), + &Insn::CheckInterrupts { state } => no_output!(gen_check_interrupts(jit, asm, &function.frame_state(state))), Insn::ArrayExtend { .. } | Insn::ArrayMax { .. } | Insn::ArrayPush { .. } @@ -674,6 +675,17 @@ fn gen_getspecial_number(asm: &mut Assembler, nth: u64, state: &FrameState) -> O asm_ccall!(asm, rb_reg_nth_match, Opnd::Imm((nth >> 1).try_into().unwrap()), backref) } +fn gen_check_interrupts(jit: &mut JITState, asm: &mut Assembler, state: &FrameState) { + // Check for interrupts + // see RUBY_VM_CHECK_INTS(ec) macro + asm_comment!(asm, "RUBY_VM_CHECK_INTS(ec)"); + // Not checking interrupt_mask since it's zero outside finalize_deferred_heap_pages, + // signal_exec, or rb_postponed_job_flush. + let interrupt_flag = asm.load(Opnd::mem(32, EC, RUBY_OFFSET_EC_INTERRUPT_FLAG)); + asm.test(interrupt_flag, interrupt_flag); + asm.jnz(side_exit(jit, state, SideExitReason::Interrupt)); +} + /// Compile an interpreter entry block to be inserted into an ISEQ fn gen_entry_prologue(asm: &mut Assembler, iseq: IseqPtr) { asm_comment!(asm, "ZJIT entry point: {}", iseq_get_location(iseq, 0)); diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index e7aaf64f28..358ecc58a9 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -440,6 +440,7 @@ pub enum SideExitReason { ObjToStringFallback, UnknownSpecialVariable(u64), UnhandledDefinedType(usize), + Interrupt, } impl std::fmt::Display for SideExitReason { @@ -600,6 +601,10 @@ pub enum Insn { /// Increment a counter in ZJIT stats IncrCounter(Counter), + + /// Equivalent of RUBY_VM_CHECK_INTS. Automatically inserted by the compiler before jumps and + /// return instructions. + CheckInterrupts { state: InsnId }, } impl Insn { @@ -610,7 +615,8 @@ impl Insn { | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetGlobal { .. } - | Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) => false, + | Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) + | Insn::CheckInterrupts { .. } => false, _ => true, } } @@ -867,6 +873,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { write!(f, ", {val}") } Insn::IncrCounter(counter) => write!(f, "IncrCounter {counter:?}"), + Insn::CheckInterrupts { .. } => write!(f, "CheckInterrupts"), } } } @@ -1292,6 +1299,7 @@ impl Function { &ToNewArray { val, state } => ToNewArray { val: find!(val), state }, &ArrayExtend { left, right, state } => ArrayExtend { left: find!(left), right: find!(right), state }, &ArrayPush { array, val, state } => ArrayPush { array: find!(array), val: find!(val), state }, + &CheckInterrupts { state } => CheckInterrupts { state }, } } @@ -1318,7 +1326,8 @@ impl Function { Insn::SetGlobal { .. } | Insn::Jump(_) | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::Throw { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } - | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetLocal { .. } | Insn::IncrCounter(_) => + | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetLocal { .. } | Insn::IncrCounter(_) + | Insn::CheckInterrupts { .. } => panic!("Cannot infer type of instruction with no output: {}", self.insns[insn.0]), Insn::Const { val: Const::Value(val) } => Type::from_value(*val), Insn::Const { val: Const::CBool(val) } => Type::from_cbool(*val), @@ -1952,6 +1961,7 @@ impl Function { | &Insn::IncrCounter(_) => {} &Insn::PatchPoint { state, .. } + | &Insn::CheckInterrupts { state } | &Insn::GetConstantPath { ic: _, state } => { worklist.push_back(state); } -- cgit v1.2.3