diff options
| -rw-r--r-- | insns.def | 3 | ||||
| -rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 9 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 85 | ||||
| -rw-r--r-- | zjit/src/profile.rs | 3 |
4 files changed, 96 insertions, 4 deletions
@@ -1553,6 +1553,7 @@ opt_length (CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_length(recv, BOP_LENGTH); @@ -1567,6 +1568,7 @@ opt_size (CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_length(recv, BOP_SIZE); @@ -1626,6 +1628,7 @@ opt_regexpmatch2 (VALUE obj2, VALUE obj1) (VALUE val) // attr bool leaf = false; /* match_at() has rb_thread_check_ints() */ +// attr bool zjit_profile = true; { val = vm_opt_regexpmatch2(obj2, obj1); diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 6e3ae05194..56b569e064 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -699,9 +699,12 @@ pub const YARVINSN_zjit_opt_and: ruby_vminsn_type = 234; pub const YARVINSN_zjit_opt_or: ruby_vminsn_type = 235; pub const YARVINSN_zjit_opt_aref: ruby_vminsn_type = 236; pub const YARVINSN_zjit_opt_aset: ruby_vminsn_type = 237; -pub const YARVINSN_zjit_opt_empty_p: ruby_vminsn_type = 238; -pub const YARVINSN_zjit_opt_not: ruby_vminsn_type = 239; -pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 240; +pub const YARVINSN_zjit_opt_length: ruby_vminsn_type = 238; +pub const YARVINSN_zjit_opt_size: ruby_vminsn_type = 239; +pub const YARVINSN_zjit_opt_empty_p: ruby_vminsn_type = 240; +pub const YARVINSN_zjit_opt_not: ruby_vminsn_type = 241; +pub const YARVINSN_zjit_opt_regexpmatch2: ruby_vminsn_type = 242; +pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 243; pub type ruby_vminsn_type = u32; pub type rb_iseq_callback = ::std::option::Option< unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void), diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 022451e8ab..33c034b819 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -4957,7 +4957,7 @@ mod tests { } #[track_caller] - fn assert_contains_opcode(method: &str, opcode: u32) { + pub fn assert_contains_opcode(method: &str, opcode: u32) { let iseq = crate::cruby::with_rubyvm(|| get_method_iseq("self", method)); unsafe { crate::cruby::rb_zjit_profile_disable(iseq) }; assert!(iseq_contains_opcode(iseq, opcode), "iseq {method} does not contain {}", insn_name(opcode as usize)); @@ -7999,6 +7999,7 @@ mod opt_tests { use super::*; use crate::{hir_strings, options::*}; use insta::assert_snapshot; + use super::tests::assert_contains_opcode; #[track_caller] fn hir_string(method: &str) -> String { @@ -12876,4 +12877,86 @@ mod opt_tests { Return v27 "); } + + #[test] + fn test_optimize_array_length() { + eval(" + def test(arr) = arr.length + test([]) + "); + assert_contains_opcode("test", YARVINSN_opt_length); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010) + PatchPoint NoSingletonClass(Array@0x1000) + v25:ArrayExact = GuardType v9, ArrayExact + v26:Fixnum = CCall length@0x1038, v25 + CheckInterrupts + Return v26 + "); + } + + #[test] + fn test_optimize_array_size() { + eval(" + def test(arr) = arr.size + test([]) + "); + assert_contains_opcode("test", YARVINSN_opt_size); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010) + PatchPoint NoSingletonClass(Array@0x1000) + v25:ArrayExact = GuardType v9, ArrayExact + v26:Fixnum = CCall size@0x1038, v25 + CheckInterrupts + Return v26 + "); + } + + #[test] + fn test_optimize_regexpmatch2() { + eval(r#" + def test(s) = s =~ /a/ + test("foo") + "#); + assert_contains_opcode("test", YARVINSN_opt_regexpmatch2); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + v13:RegexpExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + PatchPoint MethodRedefined(String@0x1008, =~@0x1010, cme:0x1018) + PatchPoint NoSingletonClass(String@0x1008) + v26:StringExact = GuardType v9, StringExact + v27:BasicObject = CCallWithFrame =~@0x1040, v26, v13 + CheckInterrupts + Return v27 + "); + } } diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs index c2c35f687b..e7db47142b 100644 --- a/zjit/src/profile.rs +++ b/zjit/src/profile.rs @@ -78,7 +78,10 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) { YARVINSN_opt_aset => profile_operands(profiler, profile, 3), YARVINSN_opt_not => profile_operands(profiler, profile, 1), YARVINSN_getinstancevariable => profile_self(profiler, profile), + YARVINSN_opt_regexpmatch2 => profile_operands(profiler, profile, 2), YARVINSN_objtostring => profile_operands(profiler, profile, 1), + YARVINSN_opt_length => profile_operands(profiler, profile, 1), + YARVINSN_opt_size => profile_operands(profiler, profile, 1), YARVINSN_opt_send_without_block => { let cd: *const rb_call_data = profiler.insn_opnd(0).as_ptr(); let argc = unsafe { vm_ci_argc((*cd).ci) }; |
