summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <max@bernsteinbear.com>2026-01-11 16:25:13 -0500
committerMax Bernstein <tekknolagi@gmail.com>2026-01-12 16:43:49 -0500
commit5cec11f45a9b6282e9bc402b599dd95159b86649 (patch)
treeae021a26a60b941af5a7dcb0fb2085788c009a25
parenta1ba9f5733711a7665b57977d78940e07ff281a5 (diff)
ZJIT: Inline Array#length
-rw-r--r--zjit/src/cruby_methods.rs14
-rw-r--r--zjit/src/hir.rs1
-rw-r--r--zjit/src/hir/opt_tests.rs50
3 files changed, 37 insertions, 28 deletions
diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs
index 4aa9068cb1..e6c26148cf 100644
--- a/zjit/src/cruby_methods.rs
+++ b/zjit/src/cruby_methods.rs
@@ -219,8 +219,7 @@ pub fn init() -> Annotations {
annotate!(rb_cString, "ascii_only?", types::BoolExact, no_gc, leaf);
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", types::Fixnum, no_gc, leaf, elidable);
- annotate!(rb_cArray, "size", types::Fixnum, no_gc, leaf, elidable);
+ 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, "reverse", types::ArrayExact, leaf, elidable);
annotate!(rb_cArray, "join", types::StringExact);
@@ -537,6 +536,17 @@ fn inline_module_eqq(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
None
}
+fn inline_array_length(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 result = fun.push_insn(block, hir::Insn::BoxFixnum { val: length_cint, state });
+ 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.rs b/zjit/src/hir.rs
index c6a104fbd1..41ddb3ae69 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1027,6 +1027,7 @@ impl Insn {
// NewHash's operands may be hashed and compared for equality, which could have
// side-effects.
Insn::NewHash { elements, .. } => !elements.is_empty(),
+ Insn::ArrayLength { .. } => false,
Insn::ArrayDup { .. } => false,
Insn::HashDup { .. } => false,
Insn::Test { .. } => false,
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 3ad07596b7..4fc47dc611 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -2291,7 +2291,7 @@ mod hir_opt_tests {
fn eliminate_array_length() {
eval("
def test
- x = [].length
+ [].length
5
end
");
@@ -2300,21 +2300,18 @@ mod hir_opt_tests {
bb0():
EntryPoint interpreter
v1:BasicObject = LoadSelf
- v2:NilClass = Const Value(nil)
- Jump bb2(v1, v2)
- bb1(v5:BasicObject):
+ Jump bb2(v1)
+ bb1(v4:BasicObject):
EntryPoint JIT(0)
- v6:NilClass = Const Value(nil)
- Jump bb2(v5, v6)
- bb2(v8:BasicObject, v9:NilClass):
- v13:ArrayExact = NewArray
+ Jump bb2(v4)
+ bb2(v6:BasicObject):
+ v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v29:Fixnum = CCall v13, :Array#length@0x1038
- v20:Fixnum[5] = Const Value(5)
+ v17:Fixnum[5] = Const Value(5)
CheckInterrupts
- Return v20
+ Return v17
");
}
@@ -2435,7 +2432,7 @@ mod hir_opt_tests {
fn eliminate_array_size() {
eval("
def test
- x = [].size
+ [].size
5
end
");
@@ -2444,21 +2441,18 @@ mod hir_opt_tests {
bb0():
EntryPoint interpreter
v1:BasicObject = LoadSelf
- v2:NilClass = Const Value(nil)
- Jump bb2(v1, v2)
- bb1(v5:BasicObject):
+ Jump bb2(v1)
+ bb1(v4:BasicObject):
EntryPoint JIT(0)
- v6:NilClass = Const Value(nil)
- Jump bb2(v5, v6)
- bb2(v8:BasicObject, v9:NilClass):
- v13:ArrayExact = NewArray
+ Jump bb2(v4)
+ bb2(v6:BasicObject):
+ v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
- v29:Fixnum = CCall v13, :Array#size@0x1038
- v20:Fixnum[5] = Const Value(5)
+ v17:Fixnum[5] = Const Value(5)
CheckInterrupts
- Return v20
+ Return v17
");
}
@@ -3554,8 +3548,9 @@ mod hir_opt_tests {
v18:ArrayExact = NewArray v11, v12
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
+ v29:CInt64 = ArrayLength v18
+ v30:Fixnum = BoxFixnum v29
IncrCounter inline_cfunc_optimized_send_count
- v30:Fixnum = CCall v18, :Array#length@0x1038
CheckInterrupts
Return v30
");
@@ -3581,8 +3576,9 @@ mod hir_opt_tests {
v18:ArrayExact = NewArray v11, v12
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
+ v29:CInt64 = ArrayLength v18
+ v30:Fixnum = BoxFixnum v29
IncrCounter inline_cfunc_optimized_send_count
- v30:Fixnum = CCall v18, :Array#size@0x1038
CheckInterrupts
Return v30
");
@@ -7170,8 +7166,9 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
+ v24:CInt64 = ArrayLength v23
+ v25:Fixnum = BoxFixnum v24
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall v23, :Array#length@0x1038
CheckInterrupts
Return v25
");
@@ -7198,8 +7195,9 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
+ v24:CInt64 = ArrayLength v23
+ v25:Fixnum = BoxFixnum v24
IncrCounter inline_cfunc_optimized_send_count
- v25:Fixnum = CCall v23, :Array#size@0x1038
CheckInterrupts
Return v25
");