diff options
| author | Max Bernstein <max@bernsteinbear.com> | 2025-07-02 14:57:09 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-02 14:57:09 -0400 |
| commit | e240b415a5286f7ec0b1edfc5a1a540c62118fd4 (patch) | |
| tree | c3d8e04ffef1acb75d438599548c1ce8c1f6c02c | |
| parent | 1d31c98e04098d406ae97fd51698533ab4933a0b (diff) | |
ZJIT: Add reason for SideExit (#13768)
This makes it clearer what is unimplemented when looking at HIR dumps.
| -rw-r--r-- | zjit/src/codegen.rs | 2 | ||||
| -rw-r--r-- | zjit/src/cruby.rs | 3 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 76 |
3 files changed, 53 insertions, 28 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 6d73a3a32d..9fa088c0d1 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -287,7 +287,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::SetLocal { val, ep_offset, level } => return gen_nested_setlocal(asm, opnd!(val), *ep_offset, *level), Insn::GetConstantPath { ic, state } => gen_get_constant_path(asm, *ic, &function.frame_state(*state)), Insn::SetIvar { self_val, id, val, state: _ } => return gen_setivar(asm, opnd!(self_val), *id, opnd!(val)), - Insn::SideExit { state } => return gen_side_exit(jit, asm, &function.frame_state(*state)), + Insn::SideExit { state, reason: _ } => return gen_side_exit(jit, asm, &function.frame_state(*state)), Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type), Insn::AnyToString { val, str, state } => gen_anytostring(asm, opnd!(val), opnd!(str), &function.frame_state(*state))?, Insn::Defined { op_type, obj, pushval, v } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v))?, diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index e5b66be850..82f0e39804 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -218,6 +218,9 @@ pub use rb_vm_get_special_object as vm_get_special_object; /// Helper so we can get a Rust string for insn_name() pub fn insn_name(opcode: usize) -> String { + if opcode >= VM_INSTRUCTION_SIZE.try_into().unwrap() { + return "<unknown>".into(); + } unsafe { // Look up Ruby's NULL-terminated insn name string let op_name = raw_insn_name(VALUE(opcode)); diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 30a6da201e..be320f6d74 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -393,6 +393,28 @@ impl PtrPrintMap { } } +#[derive(Debug, Clone)] +pub enum SideExitReason { + UnknownNewarraySend(vm_opt_newarray_send_type), + UnknownCallType, + UnknownOpcode(u32), +} + +impl std::fmt::Display for SideExitReason { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + SideExitReason::UnknownOpcode(opcode) => write!(f, "UnknownOpcode({})", insn_name(*opcode as usize)), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_MAX) => write!(f, "UnknownNewarraySend(MAX)"), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_MIN) => write!(f, "UnknownNewarraySend(MIN)"), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_HASH) => write!(f, "UnknownNewarraySend(HASH)"), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_PACK) => write!(f, "UnknownNewarraySend(PACK)"), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_PACK_BUFFER) => write!(f, "UnknownNewarraySend(PACK_BUFFER)"), + SideExitReason::UnknownNewarraySend(VM_OPT_NEWARRAY_SEND_INCLUDE_P) => write!(f, "UnknownNewarraySend(INCLUDE_P)"), + _ => write!(f, "{self:?}"), + } + } +} + /// An instruction in the SSA IR. The output of an instruction is referred to by the index of /// the instruction ([`InsnId`]). SSA form enables this, and [`UnionFind`] ([`Function::find`]) /// helps with editing. @@ -518,7 +540,7 @@ pub enum Insn { PatchPoint(Invariant), /// Side-exit into the interpreter. - SideExit { state: InsnId }, + SideExit { state: InsnId, reason: SideExitReason }, } impl Insn { @@ -714,7 +736,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::ArrayPush { array, val, .. } => write!(f, "ArrayPush {array}, {val}"), Insn::ObjToString { val, .. } => { write!(f, "ObjToString {val}") }, Insn::AnyToString { val, str, .. } => { write!(f, "AnyToString {val}, str: {str}") }, - Insn::SideExit { .. } => write!(f, "SideExit"), + Insn::SideExit { reason, .. } => write!(f, "SideExit {reason}"), Insn::PutSpecialObject { value_type } => write!(f, "PutSpecialObject {value_type}"), Insn::Throw { throw_state, val } => { let mut state_string = match throw_state & VM_THROW_STATE_MASK { @@ -1863,7 +1885,7 @@ impl Function { worklist.push_back(state); } Insn::GetGlobal { state, .. } | - Insn::SideExit { state } => worklist.push_back(state), + Insn::SideExit { state, .. } => worklist.push_back(state), } } // Now remove all unnecessary instructions @@ -2425,7 +2447,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { VM_OPT_NEWARRAY_SEND_MAX => (BOP_MAX, Insn::ArrayMax { elements, state: exit_id }), _ => { // Unknown opcode; side-exit into the interpreter - fun.push_insn(block, Insn::SideExit { state: exit_id }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownNewarraySend(method) }); break; // End the block }, }; @@ -2651,7 +2673,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { // Unknown call type; 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownCallType }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -2677,7 +2699,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { // Unknown call type; 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownCallType }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -2708,7 +2730,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { // Unknown call type; 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownCallType }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -2768,7 +2790,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { // Unknown call type; 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownCallType }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -2796,7 +2818,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { // Unknown call type; 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownCallType }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -2920,7 +2942,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { _ => { // 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 }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownOpcode(opcode) }); break; // End the block } } @@ -3962,7 +3984,7 @@ mod tests { fn test: bb0(v0:BasicObject, v1:BasicObject): v4:ArrayExact = ToArray v1 - SideExit + SideExit UnknownCallType "#]]); } @@ -3974,7 +3996,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): - SideExit + SideExit UnknownCallType "#]]); } @@ -3987,7 +4009,7 @@ mod tests { fn test: bb0(v0:BasicObject, v1:BasicObject): v3:Fixnum[1] = Const Value(1) - SideExit + SideExit UnknownCallType "#]]); } @@ -3999,7 +4021,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): - SideExit + SideExit UnknownCallType "#]]); } @@ -4013,7 +4035,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject): - SideExit + SideExit UnknownOpcode(invokesuper) "#]]); } @@ -4025,7 +4047,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject): - SideExit + SideExit UnknownOpcode(invokesuper) "#]]); } @@ -4037,7 +4059,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): - SideExit + SideExit UnknownOpcode(invokesuperforward) "#]]); } @@ -4058,7 +4080,7 @@ mod tests { v9:StaticSymbol[:b] = Const Value(VALUE(0x1008)) v10:Fixnum[1] = Const Value(1) v12:BasicObject = SendWithoutBlock v8, :core#hash_merge_ptr, v7, v9, v10 - SideExit + SideExit UnknownCallType "#]]); } @@ -4073,7 +4095,7 @@ mod tests { v4:ArrayExact = ToNewArray v1 v5:Fixnum[1] = Const Value(1) ArrayPush v4, v5 - SideExit + SideExit UnknownCallType "#]]); } @@ -4085,7 +4107,7 @@ mod tests { assert_method_hir("test", expect![[r#" fn test: bb0(v0:BasicObject, v1:BasicObject): - SideExit + SideExit UnknownOpcode(sendforward) "#]]); } @@ -4154,7 +4176,7 @@ mod tests { v3:NilClassExact = Const Value(nil) v4:NilClassExact = Const Value(nil) v7:BasicObject = SendWithoutBlock v1, :+, v2 - SideExit + SideExit UnknownNewarraySend(MIN) "#]]); } @@ -4174,7 +4196,7 @@ mod tests { v3:NilClassExact = Const Value(nil) v4:NilClassExact = Const Value(nil) v7:BasicObject = SendWithoutBlock v1, :+, v2 - SideExit + SideExit UnknownNewarraySend(HASH) "#]]); } @@ -4196,7 +4218,7 @@ mod tests { v7:BasicObject = SendWithoutBlock v1, :+, v2 v8:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v9:StringExact = StringCopy v8 - SideExit + SideExit UnknownNewarraySend(PACK) "#]]); } @@ -4218,7 +4240,7 @@ mod tests { v3:NilClassExact = Const Value(nil) v4:NilClassExact = Const Value(nil) v7:BasicObject = SendWithoutBlock v1, :+, v2 - SideExit + SideExit UnknownNewarraySend(INCLUDE_P) "#]]); } @@ -4642,7 +4664,7 @@ mod tests { v3:Fixnum[1] = Const Value(1) v5:BasicObject = ObjToString v3 v7:String = AnyToString v3, str: v5 - SideExit + SideExit UnknownOpcode(concatstrings) "#]]); } @@ -6220,7 +6242,7 @@ mod opt_tests { v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v3:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) v4:StringExact = StringCopy v3 - SideExit + SideExit UnknownOpcode(concatstrings) "#]]); } @@ -6236,7 +6258,7 @@ mod opt_tests { v3:Fixnum[1] = Const Value(1) v10:BasicObject = SendWithoutBlock v3, :to_s v7:String = AnyToString v3, str: v10 - SideExit + SideExit UnknownOpcode(concatstrings) "#]]); } |
