diff options
Diffstat (limited to 'test/ruby')
| -rw-r--r-- | test/ruby/test_proc.rb | 19 | ||||
| -rw-r--r-- | test/ruby/test_yjit.rb | 49 | ||||
| -rw-r--r-- | test/ruby/test_zjit.rb | 17 |
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']) |
