diff options
| author | Max Bernstein <ruby@bernsteinbear.com> | 2025-08-21 16:22:26 -0400 |
|---|---|---|
| committer | Max Bernstein <tekknolagi@gmail.com> | 2025-08-22 10:34:11 -0700 |
| commit | d690e8327644102386deeaeee8eb4818c24fd38b (patch) | |
| tree | 056be597f4e172c7bcfa8ea1d168d7ab85d1224a | |
| parent | e3e87258ddadf763d9b0b11678935250f9bcc6c3 (diff) | |
ZJIT: Add CheckInterrupts HIR instruction
| -rw-r--r-- | zjit/src/codegen.rs | 12 | ||||
| -rw-r--r-- | 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); } |
