summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_proc.rb19
-rw-r--r--test/ruby/test_yjit.rb49
-rw-r--r--test/ruby/test_zjit.rb17
3 files changed, 85 insertions, 0 deletions
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index f74342322f..eefd5b189b 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -342,6 +342,25 @@ class TestProc < Test::Unit::TestCase
assert_equal(9, b)
end
+ # Not named test_curry_* so that test_curry_with_trace does not re-run it
+ # under set_trace_func (which would be needlessly slow with GC.stress).
+ def test_proc_curry_keeps_args_alive
+ # The argument array passed down by `curry` must stay alive across the
+ # inner call; otherwise GC may reclaim it while it is still read as argv
+ # and crash with "try to mark T_NONE object". See the RB_GC_GUARD in `curry`.
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", timeout: 60)
+ begin;
+ GC.stress = true
+ l = ->(a, b, c) { a + b + c }
+ 30.times do
+ l1 = l.curry.call(1)
+ l2 = l1.curry.call(2)
+ assert_equal(6, l2.curry.call(3))
+ assert_equal(6, l1.curry.call(2, 3))
+ end
+ end;
+ end
+
def test_lambda?
l = proc {}
assert_equal(false, l.lambda?)
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index df7054c101..33f13511cb 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -1041,6 +1041,55 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
+ def test_bmethod_super_block_forwarding
+ # super() in a block method forwards the block handler of environment
+ # it is in. In this test, the block is in a class, which never has
+ # a block handler, so Parent#foo gets no block.
+ assert_compiles(<<~RUBY, result: nil)
+ class Parent
+ def foo = defined?(yield)
+ end
+
+ class BmethodSuper < Parent
+ define_method(:foo) { super() }
+ end
+
+ BmethodSuper.new.foo {}
+ RUBY
+
+ # For contrast, the super() here forwards the block passed to add_then_override
+ # because block with super() is rooted in add_then_override, a "def" method.
+ assert_compiles(<<~RUBY, result: [1, 2])
+ def add_then_override(object)
+ object.define_singleton_method(:then) { super() }
+ end
+
+ add_then_override(one = Object.new) { 1 }
+ add_then_override(two = Object.new) { 2 }
+ [one.then {}, two.then {}]
+ RUBY
+ end
+
+ def test_bug_22116
+ # Regression test from report which used to crash during environment escape
+ # to pass block to Hash.new
+ assert_compiles(<<~RUBY, call_threshold: 1)
+ class C
+ def foo
+ Hash.new {|h, k| h[k] = [] }
+ end
+ end
+
+ class D < C
+ define_method(:foo) do
+ super()
+ end
+ end
+
+ D.new.foo
+ RUBY
+ end
+
# Tests calling a variadic cfunc with many args
def test_build_large_struct
assert_compiles(<<~RUBY, insns: %i[opt_send_without_block], call_threshold: 2)
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
index a56fea6d51..198301d933 100644
--- a/test/ruby/test_zjit.rb
+++ b/test/ruby/test_zjit.rb
@@ -382,6 +382,23 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 14, num_profiles: 5
end
+ def test_regression_gc_stress_with_lazy_block_code
+ assert_compiles ':ok', %q{
+ def allocate_array
+ [1, 2, 3]
+ end
+
+ begin
+ GC.stress = true
+ allocate_array
+ allocate_array
+ :ok
+ ensure
+ GC.stress = false
+ end
+ }
+ end
+
def test_exit_tracing
# Smoke test: --zjit-trace-exits writes a Fuchsia trace (.fxt) file to /tmp
assert_compiles('true', <<~RUBY, extra_args: ['--zjit-trace-exits'])