summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--insns.def3
-rw-r--r--zjit/src/cruby_bindings.inc.rs9
-rw-r--r--zjit/src/hir.rs85
-rw-r--r--zjit/src/profile.rs3
4 files changed, 96 insertions, 4 deletions
diff --git a/insns.def b/insns.def
index b895bffe22..69a8210d7d 100644
--- a/insns.def
+++ b/insns.def
@@ -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) };