From 9865aa94f7de65cd8c4964c13960ca9299cbdd48 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 6 Jun 2025 21:51:05 +0900 Subject: [PATCH] ZJIT: Parse opt_empty_p into HIR --- test/ruby/test_zjit.rb | 7 +++++++ zjit/src/hir.rs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index 3b64887f92..8771a31754 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -205,6 +205,13 @@ class TestZJIT < Test::Unit::TestCase }, insns: [:opt_gt], call_threshold: 2 end + def test_opt_empty_p + assert_compiles('[false, false, true]', <<~RUBY, insns: [:opt_empty_p]) + def test(x) = x.empty? + return test([1]), test("1"), test({}) + RUBY + end + def test_opt_ge assert_compiles '[false, true, true]', %q{ def test(a, b) = a >= b diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 86e87d72ac..9ce1b94ec9 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2355,6 +2355,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { break; // Don't enqueue the next block as a successor } + // These are opt_send_without_block and all the opt_* instructions + // specialized to a certain method that could also be serviced + // using the general send implementation. The optimizer start from + // a general send for all of these later in the pipeline. YARVINSN_opt_nil_p | YARVINSN_opt_plus | YARVINSN_opt_minus | @@ -2371,6 +2375,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { YARVINSN_opt_length | YARVINSN_opt_size | YARVINSN_opt_aref | + YARVINSN_opt_empty_p | YARVINSN_opt_send_without_block => { let cd: *const rb_call_data = get_arg(pc, 0).as_ptr(); let call_info = unsafe { rb_get_call_data_ci(cd) }; @@ -3806,6 +3811,19 @@ mod tests { "#]]); } + #[test] + fn opt_empty_p() { + eval(" + def test(x) = x.empty? + "); + assert_method_hir_with_opcode("test", YARVINSN_opt_empty_p, expect![[r#" + fn test: + bb0(v0:BasicObject, v1:BasicObject): + v4:BasicObject = SendWithoutBlock v1, :empty? + Return v4 + "#]]); + } + #[test] fn test_branchnil() { eval("