diff options
-rw-r--r-- | zjit/src/hir.rs | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index a247b545fd..6029350b4b 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -402,6 +402,9 @@ pub enum Insn { /// Generate no code (or padding if necessary) and insert a patch point /// that can be rewritten to a side exit when the Invariant is broken. PatchPoint(Invariant), + + /// Side-exit into the interpreter. + SideExit { state: InsnId }, } impl Insn { @@ -411,7 +414,7 @@ impl Insn { Insn::ArraySet { .. } | Insn::Snapshot { .. } | Insn::Jump(_) | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } - | Insn::ArrayPush { .. } => false, + | Insn::ArrayPush { .. } | Insn::SideExit { .. } => false, _ => true, } } @@ -560,6 +563,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::ToNewArray { val, .. } => write!(f, "ToNewArray {val}"), Insn::ArrayExtend { left, right, .. } => write!(f, "ArrayExtend {left}, {right}"), Insn::ArrayPush { array, val, .. } => write!(f, "ArrayPush {array}, {val}"), + Insn::SideExit { .. } => write!(f, "SideExit"), insn => { write!(f, "{insn:?}") } } } @@ -915,6 +919,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 }, + &SideExit { state } => SideExit { state }, } } @@ -941,7 +946,7 @@ impl Function { Insn::ArraySet { .. } | Insn::Snapshot { .. } | Insn::Jump(_) | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } - | Insn::ArrayPush { .. } => + | Insn::ArrayPush { .. } | Insn::SideExit { .. } => panic!("Cannot infer type of instruction with no output"), Insn::Const { val: Const::Value(val) } => Type::from_value(*val), Insn::Const { val: Const::CBool(val) } => Type::from_cbool(*val), @@ -1518,6 +1523,7 @@ impl Function { worklist.push_back(val); worklist.push_back(state); } + Insn::SideExit { state } => worklist.push_back(state), } } // Now remove all unnecessary instructions @@ -1791,7 +1797,6 @@ pub enum CallType { #[derive(Debug, PartialEq)] pub enum ParseError { StackUnderflow(FrameState), - UnknownOpcode(String), UnknownNewArraySend(String), UnhandledCallType(CallType), } @@ -2243,7 +2248,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let val = state.stack_pop()?; fun.push_insn(block, Insn::SetIvar { self_val, id, val, state: exit_id }); } - _ => return Err(ParseError::UnknownOpcode(insn_name(opcode as usize))), + _ => { + // Unknown opcode; side-exit into the interpreter + 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 + } } if insn_idx_to_block.contains_key(&insn_idx) { @@ -2547,7 +2557,7 @@ mod tests { let iseq = crate::cruby::with_rubyvm(|| get_method_iseq(method)); unsafe { crate::cruby::rb_zjit_profile_disable(iseq) }; let result = iseq_to_hir(iseq); - assert!(result.is_err(), "Expected an error but succesfully compiled to HIR"); + assert!(result.is_err(), "Expected an error but succesfully compiled to HIR: {}", FunctionPrinter::without_snapshot(&result.unwrap())); assert_eq!(result.unwrap_err(), reason); } @@ -3102,7 +3112,12 @@ mod tests { eval(" def test = super() "); - assert_compile_fails("test", ParseError::UnknownOpcode("invokesuper".into())) + assert_method_hir("test", expect![[r#" + fn test: + bb0(): + v1:BasicObject = PutSelf + SideExit + "#]]); } #[test] @@ -3110,7 +3125,12 @@ mod tests { eval(" def test = super "); - assert_compile_fails("test", ParseError::UnknownOpcode("invokesuper".into())) + assert_method_hir("test", expect![[r#" + fn test: + bb0(): + v1:BasicObject = PutSelf + SideExit + "#]]); } #[test] @@ -3118,7 +3138,12 @@ mod tests { eval(" def test(...) = super(...) "); - assert_compile_fails("test", ParseError::UnknownOpcode("invokesuperforward".into())) + assert_method_hir("test", expect![[r#" + fn test: + bb0(v0:BasicObject): + v2:BasicObject = PutSelf + SideExit + "#]]); } // TODO(max): Figure out how to generate a call with OPT_SEND flag @@ -3128,7 +3153,12 @@ mod tests { eval(" def test(a) = foo **a, b: 1 "); - assert_compile_fails("test", ParseError::UnknownOpcode("putspecialobject".into())) + assert_method_hir("test", expect![[r#" + fn test: + bb0(v0:BasicObject): + v2:BasicObject = PutSelf + SideExit + "#]]); } #[test] @@ -3144,7 +3174,12 @@ mod tests { eval(" def test(...) = foo(...) "); - assert_compile_fails("test", ParseError::UnknownOpcode("sendforward".into())) + assert_method_hir("test", expect![[r#" + fn test: + bb0(v0:BasicObject): + v2:BasicObject = PutSelf + SideExit + "#]]); } #[test] |