diff options
| author | Max Bernstein <ruby@bernsteinbear.com> | 2026-01-12 11:49:13 -0500 |
|---|---|---|
| committer | Max Bernstein <tekknolagi@gmail.com> | 2026-01-12 16:43:49 -0500 |
| commit | 41d9eb784b4beba681205f7443e6c6454d0fca6e (patch) | |
| tree | 72f380ac35ed1fecde37b329fdcc8eca7b4db9e7 | |
| parent | 5cec11f45a9b6282e9bc402b599dd95159b86649 (diff) | |
ZJIT: Inline Array#empty?
| -rw-r--r-- | zjit/src/cruby_methods.rs | 15 | ||||
| -rw-r--r-- | zjit/src/hir/opt_tests.rs | 9 |
2 files changed, 20 insertions, 4 deletions
diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs index e6c26148cf..2d5bb3b62f 100644 --- a/zjit/src/cruby_methods.rs +++ b/zjit/src/cruby_methods.rs @@ -220,7 +220,7 @@ pub fn init() -> Annotations { annotate!(rb_cModule, "name", types::StringExact.union(types::NilClass), no_gc, leaf, elidable); annotate!(rb_cModule, "===", inline_module_eqq, types::BoolExact, no_gc, leaf); annotate!(rb_cArray, "length", inline_array_length, types::Fixnum, no_gc, leaf, elidable); - annotate!(rb_cArray, "empty?", types::BoolExact, no_gc, leaf, elidable); + annotate!(rb_cArray, "empty?", inline_array_empty_p, types::BoolExact, no_gc, leaf, elidable); annotate!(rb_cArray, "reverse", types::ArrayExact, leaf, elidable); annotate!(rb_cArray, "join", types::StringExact); annotate!(rb_cArray, "[]", inline_array_aref); @@ -547,6 +547,19 @@ fn inline_array_length(fun: &mut hir::Function, block: hir::BlockId, recv: hir:: None } +fn inline_array_empty_p(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> { + let &[] = args else { return None; }; + if fun.likely_a(recv, types::Array, state) { + let recv = fun.coerce_to(block, recv, types::Array, state); + let length_cint = fun.push_insn(block, hir::Insn::ArrayLength { array: recv }); + let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) }); + let result_c = fun.push_insn(block, hir::Insn::IsBitEqual { left: length_cint, right: zero }); + let result = fun.push_insn(block, hir::Insn::BoxBool { val: result_c }); + return Some(result); + } + None +} + fn inline_integer_succ(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> { if !args.is_empty() { return None; } if fun.likely_a(recv, types::Fixnum, state) { diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index 4fc47dc611..3b6f694810 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -5411,7 +5411,7 @@ mod hir_opt_tests { } #[test] - fn test_specialize_array_empty_p_to_ccall() { + fn test_specialize_array_empty_p() { eval(" def test(a) = a.empty? @@ -5431,10 +5431,13 @@ mod hir_opt_tests { PatchPoint MethodRedefined(Array@0x1000, empty?@0x1008, cme:0x1010) PatchPoint NoSingletonClass(Array@0x1000) v23:ArrayExact = GuardType v9, ArrayExact + v24:CInt64 = ArrayLength v23 + v25:CInt64[0] = Const CInt64(0) + v26:CBool = IsBitEqual v24, v25 + v27:BoolExact = BoxBool v26 IncrCounter inline_cfunc_optimized_send_count - v25:BoolExact = CCall v23, :Array#empty?@0x1038 CheckInterrupts - Return v25 + Return v27 "); } |
