summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <ruby@bernsteinbear.com>2026-01-12 11:49:13 -0500
committerMax Bernstein <tekknolagi@gmail.com>2026-01-12 16:43:49 -0500
commit41d9eb784b4beba681205f7443e6c6454d0fca6e (patch)
tree72f380ac35ed1fecde37b329fdcc8eca7b4db9e7
parent5cec11f45a9b6282e9bc402b599dd95159b86649 (diff)
ZJIT: Inline Array#empty?
-rw-r--r--zjit/src/cruby_methods.rs15
-rw-r--r--zjit/src/hir/opt_tests.rs9
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
");
}