diff options
| -rw-r--r-- | test/ruby/test_zjit.rb | 16 | ||||
| -rw-r--r-- | zjit.rb | 1 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 60 | ||||
| -rw-r--r-- | zjit/src/stats.rs | 18 |
4 files changed, 49 insertions, 46 deletions
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index fc79bdda6e..42d10490c5 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -454,6 +454,22 @@ class TestZJIT < Test::Unit::TestCase } end + def test_send_splat + assert_runs '[1, 2]', %q{ + def test(a, b) = [a, b] + def entry(arr) = test(*arr) + entry([1, 2]) + } + end + + def test_send_kwarg + assert_runs '[1, 2]', %q{ + def test(a:, b:) = [a, b] + def entry = test(a: 1, b: 2) + entry + } + end + def test_forwardable_iseq assert_compiles '1', %q{ def test(...) = 1 @@ -40,7 +40,6 @@ class << RubyVM::ZJIT stats = self.stats # Show exit reasons, ordered by the typical amount of exits for the prefix at the time - print_counters_with_prefix(prefix: 'unhandled_call_', prompt: 'unhandled call types', buf:, stats:, limit: 20) print_counters_with_prefix(prefix: 'unhandled_yarv_insn_', prompt: 'unhandled YARV insns', buf:, stats:, limit: 20) print_counters_with_prefix(prefix: 'compile_error_', prompt: 'compile error reasons', buf:, stats:, limit: 20) print_counters_with_prefix(prefix: 'exit_', prompt: 'side exit reasons', buf:, stats:, limit: 20) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 46bf38dcc6..1a268e62da 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -450,7 +450,7 @@ pub enum SideExitReason { UnknownSpecialVariable(u64), UnhandledHIRInsn(InsnId), UnhandledYARVInsn(u32), - UnhandledTailCall, + UnhandledCallType(CallType), FixnumAddOverflow, FixnumSubOverflow, FixnumMultOverflow, @@ -2968,7 +2968,8 @@ fn compute_bytecode_info(iseq: *const rb_iseq_t) -> BytecodeInfo { #[derive(Debug, PartialEq, Clone, Copy)] pub enum CallType { - BlockArg, + Splat, + Kwarg, Tailcall, } @@ -2986,8 +2987,11 @@ fn num_locals(iseq: *const rb_iseq_t) -> usize { } /// If we can't handle the type of send (yet), bail out. -fn is_tailcall(flags: u32) -> bool { - (flags & VM_CALL_TAILCALL) != 0 +fn unhandled_call_type(flags: u32) -> Result<(), CallType> { + if (flags & VM_CALL_ARGS_SPLAT) != 0 { return Err(CallType::Splat); } + if (flags & VM_CALL_KWARG) != 0 { return Err(CallType::Kwarg); } + if (flags & VM_CALL_TAILCALL) != 0 { return Err(CallType::Tailcall); } + Ok(()) } /// We have IseqPayload, which keeps track of HIR Types in the interpreter, but this is not useful @@ -3500,10 +3504,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let cd: *const rb_call_data = get_arg(pc, 1).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { - // Can't handle tailcall; side-exit into the interpreter + if let Err(call_type) = unhandled_call_type(flags) { + // Can't handle the 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -3522,10 +3526,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let cd: *const rb_call_data = get_arg(pc, 1).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { - // Can't handle tailcall; side-exit into the interpreter + if let Err(call_type) = unhandled_call_type(flags) { + // Can't handle the 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -3581,10 +3585,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let cd: *const rb_call_data = get_arg(pc, 0).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { + if let Err(call_type) = unhandled_call_type(flags) { // Can't handle tailcall; 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -3600,10 +3604,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let blockiseq: IseqPtr = get_arg(pc, 1).as_iseq(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { + if let Err(call_type) = unhandled_call_type(flags) { // Can't handle tailcall; 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -3628,10 +3632,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let cd: *const rb_call_data = get_arg(pc, 0).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { + if let Err(call_type) = unhandled_call_type(flags) { // Can't handle tailcall; 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -3658,10 +3662,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { let cd: *const rb_call_data = get_arg(pc, 0).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; let flags = unsafe { rb_vm_ci_flag(call_info) }; - if is_tailcall(flags) { + if let Err(call_type) = unhandled_call_type(flags) { // Can't handle tailcall; 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, reason: SideExitReason::UnhandledTailCall }); + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } let argc = unsafe { vm_ci_argc((*cd).ci) }; @@ -5110,9 +5114,7 @@ mod tests { fn test@<compiled>:2: bb0(v0:BasicObject, v1:BasicObject): v6:ArrayExact = ToArray v1 - v8:BasicObject = SendWithoutBlock v0, :foo, v6 - CheckInterrupts - Return v8 + SideExit UnhandledCallType(Splat) "); } @@ -5140,9 +5142,7 @@ mod tests { fn test@<compiled>:2: bb0(v0:BasicObject, v1:BasicObject): v5:Fixnum[1] = Const Value(1) - v7:BasicObject = SendWithoutBlock v0, :foo, v5 - CheckInterrupts - Return v7 + SideExit UnhandledCallType(Kwarg) "); } @@ -5264,9 +5264,7 @@ mod tests { v6:ArrayExact = ToNewArray v1 v7:Fixnum[1] = Const Value(1) ArrayPush v6, v7 - v11:BasicObject = SendWithoutBlock v0, :foo, v6 - CheckInterrupts - Return v11 + SideExit UnhandledCallType(Splat) "); } @@ -7862,9 +7860,7 @@ mod opt_tests { fn test@<compiled>:3: bb0(v0:BasicObject): v4:Fixnum[1] = Const Value(1) - v6:BasicObject = SendWithoutBlock v0, :foo, v4 - CheckInterrupts - Return v6 + SideExit UnhandledCallType(Kwarg) "); } @@ -7880,9 +7876,7 @@ mod opt_tests { fn test@<compiled>:3: bb0(v0:BasicObject): v4:Fixnum[1] = Const Value(1) - v6:BasicObject = SendWithoutBlock v0, :foo, v4 - CheckInterrupts - Return v6 + SideExit UnhandledCallType(Kwarg) "); } diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 69748f4ebc..0eb2b8687b 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -93,6 +93,8 @@ make_counters! { exit_compile_error, exit_unknown_newarray_send, exit_unhandled_tailcall, + exit_unhandled_splat, + exit_unhandled_kwarg, exit_unknown_special_variable, exit_unhandled_hir_insn, exit_unhandled_yarv_insn, @@ -162,17 +164,6 @@ pub fn exit_counter_ptr_for_opcode(opcode: u32) -> *mut u64 { unsafe { exit_counters.get_unchecked_mut(opcode as usize) } } -/// Return a raw pointer to the exit counter for a given call type -pub fn exit_counter_ptr_for_call_type(call_type: crate::hir::CallType) -> *mut u64 { - use crate::hir::CallType::*; - use crate::stats::Counter::*; - let counter = match call_type { - BlockArg => unhandled_call_block_arg, - Tailcall => unhandled_call_tailcall, - }; - counter_ptr(counter) -} - /// Reason why ZJIT failed to produce any JIT code #[derive(Clone, Debug, PartialEq)] pub enum CompileError { @@ -206,10 +197,13 @@ pub fn exit_counter_for_compile_error(compile_error: &CompileError) -> Counter { pub fn exit_counter_ptr(reason: crate::hir::SideExitReason) -> *mut u64 { use crate::hir::SideExitReason::*; + use crate::hir::CallType::*; use crate::stats::Counter::*; let counter = match reason { UnknownNewarraySend(_) => exit_unknown_newarray_send, - UnhandledTailCall => exit_unhandled_tailcall, + UnhandledCallType(Tailcall) => exit_unhandled_tailcall, + UnhandledCallType(Splat) => exit_unhandled_splat, + UnhandledCallType(Kwarg) => exit_unhandled_kwarg, UnknownSpecialVariable(_) => exit_unknown_special_variable, UnhandledHIRInsn(_) => exit_unhandled_hir_insn, UnhandledYARVInsn(_) => exit_unhandled_yarv_insn, |
