summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <ruby@bernsteinbear.com>2025-08-21 16:22:26 -0400
committerMax Bernstein <tekknolagi@gmail.com>2025-08-22 10:34:11 -0700
commitd690e8327644102386deeaeee8eb4818c24fd38b (patch)
tree056be597f4e172c7bcfa8ea1d168d7ab85d1224a
parente3e87258ddadf763d9b0b11678935250f9bcc6c3 (diff)
ZJIT: Add CheckInterrupts HIR instruction
-rw-r--r--zjit/src/codegen.rs12
-rw-r--r--zjit/src/hir.rs14
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);
}