From 917c02246fbb5ccc182cdadfff5539687d88170c Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Mon, 16 Jun 2025 22:16:29 -0400 Subject: [PATCH] ZJIT: SideExit on optional args We haven't implemented optional args yet, so `SideExit` for now. Prior to this commit `def test(a=true) a` would compile to: ``` fn test: bb0(v0:BasicObject, v1:BasicObject): v3:TrueClassExact = Const Value(true) Return v3 ``` But that is only correct for the case where the caller does not pass in the optional arg. We probably need a guard on the PC similar to what YJIT has. --- zjit/src/hir.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index c67f25451a9afd..6ce30102a17b9b 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2127,6 +2127,13 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { let exit_state = state.clone(); profiles.profile_stack(&exit_state); + // TODO: Remove this and implement optional arguments + if unsafe { get_iseq_flags_has_opt(iseq) } { + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + fun.push_insn(block, Insn::SideExit { state: exit_id }); + break; // End the block + } + // try_into() call below is unfortunate. Maybe pick i32 instead of usize for opcodes. let opcode: u32 = unsafe { rb_iseq_opcode_at_pc(iseq, pc) } .try_into() @@ -3476,6 +3483,18 @@ mod tests { "#]]); } + #[test] + fn test_cant_compile_optional_arg() { + eval(" + def test(a=nil) = a + "); + assert_method_hir("test", expect![[r#" + fn test: + bb0(v0:BasicObject, v1:BasicObject): + SideExit + "#]]); + } + #[test] fn test_cant_compile_splat() { eval("