summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_zjit.rb16
-rw-r--r--zjit.rb1
-rw-r--r--zjit/src/hir.rs60
-rw-r--r--zjit/src/stats.rs18
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
diff --git a/zjit.rb b/zjit.rb
index d6f7a40692..44bce453ff 100644
--- a/zjit.rb
+++ b/zjit.rb
@@ -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,