Skip to content

Commit a0bf36a

Browse files
authored
ZJIT: Annotate NilClass#nil? and Kernel#nil?
These methods return fixed `true` or `false` so we can be certain about their return types.
1 parent ddb8de1 commit a0bf36a

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

test/ruby/test_zjit.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,20 @@ def test(x)
840840
}, call_threshold: 1, insns: [:branchnil]
841841
end
842842

843+
def test_nil_nil
844+
assert_compiles 'true', %q{
845+
def test = nil.nil?
846+
test
847+
}, insns: [:opt_nil_p]
848+
end
849+
850+
def test_non_nil_nil
851+
assert_compiles 'false', %q{
852+
def test = 1.nil?
853+
test
854+
}, insns: [:opt_nil_p]
855+
end
856+
843857
# tool/ruby_vm/views/*.erb relies on the zjit instructions a) being contiguous and
844858
# b) being reliably ordered after all the other instructions.
845859
def test_instruction_order

zjit/src/cruby_methods.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub fn init() -> Annotations {
8080
annotate!(rb_cModule, "===", types::BoolExact, no_gc, leaf);
8181
annotate!(rb_cArray, "length", types::Fixnum, no_gc, leaf, elidable);
8282
annotate!(rb_cArray, "size", types::Fixnum, no_gc, leaf, elidable);
83+
annotate!(rb_cNilClass, "nil?", types::TrueClassExact, no_gc, leaf, elidable);
84+
annotate!(rb_mKernel, "nil?", types::FalseClassExact, no_gc, leaf, elidable);
8385

8486
Annotations {
8587
cfuncs: std::mem::take(cfuncs)

zjit/src/hir.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6368,4 +6368,68 @@ mod opt_tests {
63686368
Return v2
63696369
"#]]);
63706370
}
6371+
6372+
#[test]
6373+
fn test_nil_nil_specialized_to_ccall() {
6374+
eval("
6375+
def test = nil.nil?
6376+
");
6377+
assert_optimized_method_hir("test", expect![[r#"
6378+
fn test:
6379+
bb0(v0:BasicObject):
6380+
v2:NilClassExact = Const Value(nil)
6381+
PatchPoint MethodRedefined(NilClass@0x1000, nil?@0x1008)
6382+
v7:TrueClassExact = CCall nil?@0x1010, v2
6383+
Return v7
6384+
"#]]);
6385+
}
6386+
6387+
#[test]
6388+
fn test_eliminate_nil_nil_specialized_to_ccall() {
6389+
eval("
6390+
def test
6391+
nil.nil?
6392+
1
6393+
end
6394+
");
6395+
assert_optimized_method_hir("test", expect![[r#"
6396+
fn test:
6397+
bb0(v0:BasicObject):
6398+
PatchPoint MethodRedefined(NilClass@0x1000, nil?@0x1008)
6399+
v5:Fixnum[1] = Const Value(1)
6400+
Return v5
6401+
"#]]);
6402+
}
6403+
6404+
#[test]
6405+
fn test_non_nil_nil_specialized_to_ccall() {
6406+
eval("
6407+
def test = 1.nil?
6408+
");
6409+
assert_optimized_method_hir("test", expect![[r#"
6410+
fn test:
6411+
bb0(v0:BasicObject):
6412+
v2:Fixnum[1] = Const Value(1)
6413+
PatchPoint MethodRedefined(Integer@0x1000, nil?@0x1008)
6414+
v7:FalseClassExact = CCall nil?@0x1010, v2
6415+
Return v7
6416+
"#]]);
6417+
}
6418+
6419+
#[test]
6420+
fn test_eliminate_non_nil_nil_specialized_to_ccall() {
6421+
eval("
6422+
def test
6423+
1.nil?
6424+
2
6425+
end
6426+
");
6427+
assert_optimized_method_hir("test", expect![[r#"
6428+
fn test:
6429+
bb0(v0:BasicObject):
6430+
PatchPoint MethodRedefined(Integer@0x1000, nil?@0x1008)
6431+
v5:Fixnum[2] = Const Value(2)
6432+
Return v5
6433+
"#]]);
6434+
}
63716435
}

0 commit comments

Comments
 (0)