summaryrefslogtreecommitdiff
path: root/bootstraptest
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2026-02-09 16:46:50 -0500
committerAlan Wu <XrXr@users.noreply.github.com>2026-02-18 10:16:43 -0500
commitea7d3eb89b8c5192c0cf9a885a17b0aeaef1067a (patch)
treec669740a109e20a257ec3b834be30777b6b1e329 /bootstraptest
parentd256629bf9e194838d1837be74dcc0b8ff0bcfd6 (diff)
YJIT: Fix always-failing guard for `super()` in BMETHODs
Previously, when dealing with a `super()` nested in a block that runs as a method (through e.g. `define_method`), YJIT generated a guard that never passes leading to a misidentification of the callsite as megamorphic and an unconditional interpreter fallback. The issue was in the subroutine to find the currently running method entry. In the interpreter, this is rb_vm_frame_method_entry(). YJIT used `gen_get_lep()` to find the EP with `VM_ENV_FLAG_LOCAL`, but in case of BMETHODs, the corresponding CME is never at an EP level with `VM_ENV_FLAG_LOCAL` set. Because each block nesting level can dynamically run as either a BMETHOD or not, starting at a block and finding the first EP that has a method entry ultimately requires a search loop such as the one in rb_vm_frame_method_entry(). This patch introduces such a loop. Because `invokesuper` in a block can now work end-to-end, add check for the previously masked "implicit argument passing of super from method defined by define_method() is not supported..." condition.
Diffstat (limited to 'bootstraptest')
-rw-r--r--bootstraptest/test_yjit.rb26
1 files changed, 26 insertions, 0 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index be66395190..cc7d9f1aeb 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -2483,6 +2483,32 @@ assert_equal '[0, 2]', %q{
B.new.foo
}
+# invokesuper in a weird block
+assert_equal '["block->A#itself", "block->singleton#itself"]', %q{
+ # This test runs the same block as first as a block and then as a method,
+ # testing the routine that finds the currently running method, which is
+ # relevant for `super`.
+ class BlockIseqDuality
+ prepend(Module.new do
+ def itself
+ nested = -> { "block->" + super() }
+ @singleton_itself.define_singleton_method(:itself, &nested)
+ nested
+ end
+ end)
+
+ attr_reader :singleton_itself
+ def initialize = (@singleton_itself = "singleton#itself")
+
+ def itself = "A#itself"
+ end
+
+ tester = BlockIseqDuality.new
+ super_lambda = tester.itself
+ super_lambda.call # warmup
+ [super_lambda.call, tester.singleton_itself.itself]
+}
+
# invokesuper zsuper in a bmethod
assert_equal 'ok', %q{
class Foo