summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2025-10-31 18:58:21 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2025-10-31 19:32:00 -0400
commit8db30094fce210cd193b571d7c4b7e5702ed1ca9 (patch)
treebdac354e25297303f5fb21c497147adb8f407622
parentcc8cfbcd8592cb003c58558ce63c117461a5ef32 (diff)
ZJIT: Fix incorrect elision of call to BasicObject#!=
rb_obj_not_equal() uses rb_funcall(), so it's not `no_gc`, `leaf`, nor `elidable`.
-rw-r--r--zjit/src/cruby_methods.rs2
-rw-r--r--zjit/src/hir/opt_tests.rs46
2 files changed, 47 insertions, 1 deletions
diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs
index bd3409ff07..0af3be1819 100644
--- a/zjit/src/cruby_methods.rs
+++ b/zjit/src/cruby_methods.rs
@@ -221,7 +221,7 @@ pub fn init() -> Annotations {
annotate!(rb_mKernel, "respond_to?", inline_kernel_respond_to_p);
annotate!(rb_cBasicObject, "==", inline_basic_object_eq, types::BoolExact, no_gc, leaf, elidable);
annotate!(rb_cBasicObject, "!", types::BoolExact, no_gc, leaf, elidable);
- annotate!(rb_cBasicObject, "!=", inline_basic_object_neq, types::BoolExact, no_gc, leaf, elidable);
+ annotate!(rb_cBasicObject, "!=", inline_basic_object_neq, types::BoolExact);
annotate!(rb_cBasicObject, "initialize", inline_basic_object_initialize);
annotate!(rb_cInteger, "succ", inline_integer_succ);
annotate!(rb_cInteger, "^", inline_integer_xor);
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 8a9acb59bb..d0b3203ac1 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -503,6 +503,52 @@ mod hir_opt_tests {
}
#[test]
+ fn neq_with_side_effect_not_elided () {
+ let result = eval("
+ class CustomEq
+ attr_reader :count
+
+ def ==(o)
+ @count = @count.to_i + 1
+ self.equal?(o)
+ end
+ end
+
+ def test(object)
+ # intentionally unused, but also can't assign to underscore
+ object != object
+ nil
+ end
+
+ custom = CustomEq.new
+ test(custom)
+ test(custom)
+
+ custom.count
+ ");
+ assert_eq!(VALUE::fixnum_from_usize(2), result);
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@<compiled>:13:
+ 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(CustomEq@0x1000, !=@0x1008, cme:0x1010)
+ PatchPoint NoSingletonClass(CustomEq@0x1000)
+ v28:HeapObject[class_exact:CustomEq] = GuardType v9, HeapObject[class_exact:CustomEq]
+ v29:BoolExact = CCallWithFrame !=@0x1038, v28, v9
+ v19:NilClass = Const Value(nil)
+ CheckInterrupts
+ Return v19
+ ");
+ }
+
+ #[test]
fn test_replace_guard_if_known_fixnum() {
eval("
def test(a)