summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_yjit.rb21
-rw-r--r--yjit/src/codegen.rs24
2 files changed, 33 insertions, 12 deletions
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 5347028550..cc9507aff4 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -547,8 +547,7 @@ class TestYJIT < Test::Unit::TestCase
end
def test_getblockparamproxy
- # Currently two side exits as OPTIMIZED_METHOD_TYPE_CALL is unimplemented
- assert_compiles(<<~'RUBY', insns: [:getblockparamproxy])
+ assert_compiles(<<~'RUBY', insns: [:getblockparamproxy], exits: {})
def foo &blk
p blk.call
p blk.call
@@ -559,6 +558,24 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_ifunc_getblockparamproxy
+ assert_compiles(<<~'RUBY', insns: [:getblockparamproxy], exits: {})
+ class Foo
+ include Enumerable
+
+ def each(&block)
+ block.call 1
+ block.call 2
+ block.call 3
+ end
+ end
+
+ foo = Foo.new
+ foo.map { _1 * 2 }
+ foo.map { _1 * 2 }
+ RUBY
+ end
+
def test_send_blockarg
assert_compiles(<<~'RUBY', insns: [:getblockparamproxy, :send], exits: {})
def bar
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index c506b4360c..b51704b2c6 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -8151,9 +8151,10 @@ fn gen_getblockparamproxy(
// Peek at the block handler so we can check whether it's nil
let comptime_handler = jit.peek_at_block_handler(level);
- // Filter for the 3 cases we currently handle
+ // Filter for the 4 cases we currently handle
if !(comptime_handler.as_u64() == 0 || // no block given
comptime_handler.as_u64() & 0x3 == 0x1 || // iseq block (no associated GC managed object)
+ comptime_handler.as_u64() & 0x3 == 0x3 || // ifunc block (no associated GC managed object)
unsafe { rb_obj_is_proc(comptime_handler) }.test() // block is a Proc
) {
// Missing the symbol case, where we basically need to call Symbol#to_proc at runtime
@@ -8181,7 +8182,7 @@ fn gen_getblockparamproxy(
// Use block handler sample to guide specialization...
// NOTE: we use jit_chain_guard() in this decision tree, and since
- // there are only 3 cases, it should never reach the depth limit use
+ // there are only a few cases, it should never reach the depth limit use
// the exit counter we pass to it.
//
// No block given
@@ -8199,15 +8200,18 @@ fn gen_getblockparamproxy(
);
jit_putobject(asm, Qnil);
- } else if comptime_handler.as_u64() & 0x3 == 0x1 {
- // Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
- let block_handler = asm.and(block_handler, 0x3.into());
-
- // Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null.
- asm.cmp(block_handler, 0x1.into());
-
+ } else if comptime_handler.as_u64() & 0x1 == 0x1 {
+ // This handles two cases which are nearly identical
+ // Block handler is a tagged pointer. Look at the tag.
+ // VM_BH_ISEQ_BLOCK_P(): block_handler & 0x03 == 0x01
+ // VM_BH_IFUNC_P(): block_handler & 0x03 == 0x03
+ // So to check for either of those cases we can use: val & 0x1 == 0x1
+ const _: () = assert!(RUBY_SYMBOL_FLAG & 1 == 0, "guard below rejects symbol block handlers");
+ // Procs are aligned heap pointers so testing the bit rejects them too.
+
+ asm.test(block_handler, 0x1.into());
jit_chain_guard(
- JCC_JNZ,
+ JCC_JZ,
jit,
asm,
ocb,