summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2026-02-10 09:32:37 -0800
committerGitHub <noreply@github.com>2026-02-10 09:32:37 -0800
commitacacbec35943a1fd3dd58af54d78fb878d80aae4 (patch)
treef8bde567d8f15adb776e835e69f8e80f8761443b /test/ruby
parent1a3ba1b6dd202ffe27d5adfc63e767684b559921 (diff)
ZJIT: Move JIT code tests from test_zjit.rb to Rust (#16130)
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_zjit.rb4494
1 files changed, 0 insertions, 4494 deletions
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
index 095b690c7b..333e34e927 100644
--- a/test/ruby/test_zjit.rb
+++ b/test/ruby/test_zjit.rb
@@ -112,167 +112,6 @@ class TestZJIT < Test::Unit::TestCase
RUBY
end
- def test_call_itself
- assert_compiles '42', <<~RUBY, call_threshold: 2
- def test = 42.itself
- test
- test
- RUBY
- end
-
- def test_nil
- assert_compiles 'nil', %q{
- def test = nil
- test
- }
- end
-
- def test_putobject
- assert_compiles '1', %q{
- def test = 1
- test
- }
- end
-
- def test_putstring
- assert_compiles '""', %q{
- def test = "#{""}"
- test
- }, insns: [:putstring]
- end
-
- def test_putchilldedstring
- assert_compiles '""', %q{
- def test = ""
- test
- }, insns: [:putchilledstring]
- end
-
- def test_leave_param
- assert_compiles '5', %q{
- def test(n) = n
- test(5)
- }
- end
-
- def test_getglobal_with_warning
- assert_compiles('"rescued"', %q{
- Warning[:deprecated] = true
-
- module Warning
- def warn(message)
- raise
- end
- end
-
- def test
- $=
- rescue
- "rescued"
- end
-
- $VERBOSE = true
- test
- }, insns: [:getglobal])
- end
-
- def test_setglobal
- assert_compiles '1', %q{
- def test
- $a = 1
- $a
- end
-
- test
- }, insns: [:setglobal]
- end
-
- def test_string_intern
- assert_compiles ':foo123', %q{
- def test
- :"foo#{123}"
- end
-
- test
- }, insns: [:intern]
- end
-
- def test_duphash
- assert_compiles '{a: 1}', %q{
- def test
- {a: 1}
- end
-
- test
- }, insns: [:duphash]
- end
-
- def test_pushtoarray
- assert_compiles '[1, 2, 3]', %q{
- def test
- [*[], 1, 2, 3]
- end
- test
- }, insns: [:pushtoarray]
- end
-
- def test_splatarray_new_array
- assert_compiles '[1, 2, 3]', %q{
- def test a
- [*a, 3]
- end
- test [1, 2]
- }, insns: [:splatarray]
- end
-
- def test_splatarray_existing_array
- assert_compiles '[1, 2, 3]', %q{
- def foo v
- [1, 2, v]
- end
- def test a
- foo(*a)
- end
- test [3]
- }, insns: [:splatarray]
- end
-
- def test_concattoarray
- assert_compiles '[1, 2, 3]', %q{
- def test(*a)
- [1, 2, *a]
- end
- test 3
- }, insns: [:concattoarray]
- end
-
- def test_definedivar
- assert_compiles '[nil, "instance-variable", nil]', %q{
- def test
- v0 = defined?(@a)
- @a = nil
- v1 = defined?(@a)
- remove_instance_variable :@a
- v2 = defined?(@a)
- [v0, v1, v2]
- end
- test
- }, insns: [:definedivar]
- end
-
- def test_setglobal_with_trace_var_exception
- assert_compiles '"rescued"', %q{
- def test
- $a = 1
- rescue
- "rescued"
- end
-
- trace_var(:$a) { raise }
- test
- }, insns: [:setglobal]
- end
-
def test_toplevel_binding
# Not using assert_compiles, which doesn't use the toplevel frame for `test_script`.
out, err, status = eval_with_jit(%q{
@@ -286,391 +125,6 @@ class TestZJIT < Test::Unit::TestCase
assert_equal "[1, 3, 4]", out
end
- def test_toplevel_local_after_eval
- # Not using assert_compiles, which doesn't use the toplevel frame for `test_script`.
- out, err, status = eval_with_jit(%q{
- a = 1
- b = 2
- eval('b = 3')
- c = 4
- print [a, b, c]
- })
- assert_success(out, err, status)
- assert_equal "[1, 3, 4]", out
- end
-
- def test_getlocal_after_eval
- assert_compiles '2', %q{
- def test
- a = 1
- eval('a = 2')
- a
- end
- test
- }
- end
-
- def test_getlocal_after_instance_eval
- assert_compiles '2', %q{
- def test
- a = 1
- instance_eval('a = 2')
- a
- end
- test
- }
- end
-
- def test_getlocal_after_module_eval
- assert_compiles '2', %q{
- def test
- a = 1
- Kernel.module_eval('a = 2')
- a
- end
- test
- }
- end
-
- def test_getlocal_after_class_eval
- assert_compiles '2', %q{
- def test
- a = 1
- Kernel.class_eval('a = 2')
- a
- end
- test
- }
- end
-
- def test_setlocal
- assert_compiles '3', %q{
- def test(n)
- m = n
- m
- end
- test(3)
- }
- end
-
- def test_return_nonparam_local
- # Use dead code (if false) to create a local without initialization instructions.
- assert_compiles 'nil', %q{
- def foo(a)
- if false
- x = nil
- end
- x
- end
- def test = foo(1)
- test
- test
- }, call_threshold: 2
- end
-
- def test_nonparam_local_nil_in_jit_call
- # Non-parameter locals must be initialized to nil in JIT-to-JIT calls.
- # Use dead code (if false) to create locals without initialization instructions.
- # Then eval a string that accesses the uninitialized locals.
- assert_compiles '["x", "x", "x", "x"]', %q{
- def f(a)
- a ||= 1
- if false; b = 1; end
- eval("-> { p 'x#{b}' }")
- end
-
- 4.times.map { f(1).call }
- }, call_threshold: 2
- end
-
- def test_kwargs_with_exit_and_local_invalidation
- assert_compiles ':ok', %q{
- def a(b:, c:)
- if c == :b
- return -> {}
- end
- Class # invalidate locals
-
- raise "c is :b!" if c == :b
- end
-
- def test
- # note opposite order of kwargs
- a(c: :c, b: :b)
- end
-
- 4.times { test }
- :ok
- }, call_threshold: 2
- end
-
- def test_kwargs_with_max_direct_send_arg_count
- # Ensure that we only reorder the args when we _can_ use direct send (< 6 args).
- assert_compiles '[[1, 2, 3, 4, 5, 6, 7, 8]]', %q{
- def kwargs(five, six, a:, b:, c:, d:, e:, f:)
- [a, b, c, d, five, six, e, f]
- end
-
- 5.times.flat_map do
- [
- kwargs(5, 6, d: 4, c: 3, a: 1, b: 2, e: 7, f: 8),
- kwargs(5, 6, d: 4, c: 3, b: 2, a: 1, e: 7, f: 8)
- ]
- end.uniq
- }, call_threshold: 2
- end
-
- def test_setlocal_on_eval
- assert_compiles '1', %q{
- @b = binding
- eval('a = 1', @b)
- eval('a', @b)
- }
- end
-
- def test_optional_arguments
- assert_compiles '[[1, 2, 3], [10, 20, 3], [100, 200, 300]]', %q{
- def test(a, b = 2, c = 3)
- [a, b, c]
- end
- [test(1), test(10, 20), test(100, 200, 300)]
- }
- end
-
- def test_optional_arguments_setlocal
- assert_compiles '[[2, 2], [1, nil]]', %q{
- def test(a = (b = 2))
- [a, b]
- end
- [test, test(1)]
- }
- end
-
- def test_optional_arguments_cyclic
- assert_compiles '[nil, 1]', %q{
- test = proc { |a=a| a }
- [test.call, test.call(1)]
- }
- end
-
- def test_optional_arguments_side_exit
- # This leads to FailedOptionalArguments, so not using assert_compiles
- assert_runs '[:foo, nil, 1]', %q{
- def test(a = (def foo = nil)) = a
- [test, (undef :foo), test(1)]
- }
- end
-
- def test_getblockparamproxy
- assert_compiles '1', %q{
- def test(&block)
- 0.then(&block)
- end
- test { 1 }
- }, insns: [:getblockparamproxy]
- end
-
- def test_getblockparam
- assert_compiles '2', %q{
- def test(&blk)
- blk
- end
- test { 2 }.call
- test { 2 }.call
- }, insns: [:getblockparam]
- end
-
- def test_getblockparam_proxy_side_exit_restores_block_local
- assert_compiles '2', %q{
- def test(&block)
- b = block
- # sideexits here
- raise "test" unless block
- b ? 2 : 3
- end
- test {}
- test {}
- }, insns: [:getblockparam, :getblockparamproxy]
- end
-
- def test_getblockparam_used_twice_in_args
- assert_compiles '1', %q{
- def f(*args) = args
- def test(&blk)
- b = blk
- f(*[1], blk)
- blk
- end
- test {1}.call
- test {1}.call
- }, insns: [:getblockparam]
- end
-
- def test_optimized_method_call_proc_call
- assert_compiles '2', %q{
- p = proc { |x| x * 2 }
- def test(p)
- p.call(1)
- end
- test(p)
- test(p)
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_optimized_method_call_proc_aref
- assert_compiles '4', %q{
- p = proc { |x| x * 2 }
- def test(p)
- p[2]
- end
- test(p)
- test(p)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_optimized_method_call_proc_yield
- assert_compiles '6', %q{
- p = proc { |x| x * 2 }
- def test(p)
- p.yield(3)
- end
- test(p)
- test(p)
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_optimized_method_call_proc_kw_splat
- assert_compiles '3', %q{
- p = proc { |**kw| kw[:a] + kw[:b] }
- def test(p, h)
- p.call(**h)
- end
- h = { a: 1, b: 2 }
- test(p, h)
- test(p, h)
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_optimized_method_call_proc_call_splat
- assert_compiles '43', %q{
- p = proc { |x| x + 1 }
- def test(p)
- ary = [42]
- p.call(*ary)
- end
- test(p)
- test(p)
- }, call_threshold: 2
- end
-
- def test_optimized_method_call_proc_call_kwarg
- assert_compiles '1', %q{
- p = proc { |a:| a }
- def test(p)
- p.call(a: 1)
- end
- test(p)
- test(p)
- }, call_threshold: 2
- end
-
- def test_call_a_forwardable_method
- assert_runs '[]', %q{
- def test_root = forwardable
- def forwardable(...) = Array.[](...)
- test_root
- test_root
- }, call_threshold: 2
- end
-
- def test_setlocal_on_eval_with_spill
- assert_compiles '1', %q{
- @b = binding
- eval('a = 1; itself', @b)
- eval('a', @b)
- }
- end
-
- def test_nested_local_access
- assert_compiles '[1, 2, 3]', %q{
- 1.times do |l2|
- 1.times do |l1|
- define_method(:test) do
- l1 = 1
- l2 = 2
- l3 = 3
- [l1, l2, l3]
- end
- end
- end
-
- test
- test
- test
- }, call_threshold: 3, insns: [:getlocal, :setlocal, :getlocal_WC_0, :setlocal_WC_1]
- end
-
- def test_send_with_local_written_by_blockiseq
- assert_compiles '[1, 2]', %q{
- def test
- l1 = nil
- l2 = nil
- tap do |_|
- l1 = 1
- tap do |_|
- l2 = 2
- end
- end
-
- [l1, l2]
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_without_block
- assert_compiles '[1, 2, 3]', %q{
- def foo = 1
- def bar(a) = a - 1
- def baz(a, b) = a - b
-
- def test1 = foo
- def test2 = bar(3)
- def test3 = baz(4, 1)
-
- [test1, test2, test3]
- }
- end
-
- def test_send_with_six_args
- assert_compiles '[1, 2, 3, 4, 5, 6]', %q{
- def foo(a1, a2, a3, a4, a5, a6)
- [a1, a2, a3, a4, a5, a6]
- end
-
- def test
- foo(1, 2, 3, 4, 5, 6)
- end
-
- test # profile send
- test
- }, call_threshold: 2
- end
-
- def test_send_on_heap_object_in_spilled_arg
- # This leads to a register spill, so not using `assert_compiles`
- assert_runs 'Hash', %q{
- def entry(a1, a2, a3, a4, a5, a6, a7, a8, a9)
- a9.itself.class
- end
-
- entry(1, 2, 3, 4, 5, 6, 7, 8, {}) # profile
- entry(1, 2, 3, 4, 5, 6, 7, 8, {})
- }, call_threshold: 2
- end
-
def test_send_exit_with_uninitialized_locals
assert_runs 'nil', %q{
def entry(init)
@@ -687,1467 +141,6 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 2, allowed_iseqs: 'entry@-e:2'
end
- def test_send_optional_arguments
- assert_compiles '[[1, 2], [3, 4]]', %q{
- def test(a, b = 2) = [a, b]
- def entry = [test(1), test(3, 4)]
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_nil_block_arg
- assert_compiles 'false', %q{
- def test = block_given?
- def entry = test(&nil)
- test
- }
- end
-
- def test_send_symbol_block_arg
- assert_compiles '["1", "2"]', %q{
- def test = [1, 2].map(&:to_s)
- test
- }
- end
-
- def test_send_variadic_with_block
- assert_compiles '[[1, "a"], [2, "b"], [3, "c"]]', %q{
- A = [1, 2, 3]
- B = ["a", "b", "c"]
-
- def test
- result = []
- A.zip(B) { |x, y| result << [x, y] }
- result
- end
-
- test; test
- }, call_threshold: 2
- end
-
- def test_send_splat
- assert_runs '[1, 2]', %q{
- def test(a, b) = [a, b]
- def entry(arr) = test(*arr)
- entry([1, 2])
- }
- end
-
- def test_send_kwarg
- assert_runs '[1, 2]', %q{
- def test(a:, b:) = [a, b]
- def entry = test(b: 2, a: 1) # change order
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_optional
- assert_compiles '[1, 2]', %q{
- def test(a: 1, b: 2) = [a, b]
- def entry = test
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_optional_too_many
- assert_compiles '[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]', %q{
- def test(a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10) = [a, b, c, d, e, f, g, h, i, j]
- def entry = test
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_required_and_optional
- assert_compiles '[3, 2]', %q{
- def test(a:, b: 2) = [a, b]
- def entry = test(a: 3)
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_to_hash
- assert_compiles '{a: 3}', %q{
- def test(hash) = hash
- def entry = test(a: 3)
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_to_ccall
- assert_compiles '["a", "b", "c"]', %q{
- def test(s) = s.each_line(chomp: true).to_a
- def entry = test(%(a\nb\nc))
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_and_block_to_ccall
- assert_compiles '["a", "b", "c"]', %q{
- def test(s)
- a = []
- s.each_line(chomp: true) { |l| a << l }
- a
- end
- def entry = test(%(a\nb\nc))
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_with_too_many_args_to_c_call
- assert_compiles '"a b c d {kwargs: :e}"', %q{
- def test(a:, b:, c:, d:, e:) = sprintf("%s %s %s %s %s", a, b, c, d, kwargs: e)
- def entry = test(e: :e, d: :d, c: :c, a: :a, b: :b)
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwsplat
- assert_compiles '3', %q{
- def test(a:) = a
- def entry = test(**{a: 3})
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwrest
- assert_compiles '{a: 3}', %q{
- def test(**kwargs) = kwargs
- def entry = test(a: 3)
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_req_kwreq
- assert_compiles '[1, 3]', %q{
- def test(a, c:) = [a, c]
- def entry = test(1, c: 3)
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_req_opt_kwreq
- assert_compiles '[[1, 2, 3], [-1, -2, -3]]', %q{
- def test(a, b = 2, c:) = [a, b, c]
- def entry = [test(1, c: 3), test(-1, -2, c: -3)] # specify all, change kw order
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_req_opt_kwreq_kwopt
- assert_compiles '[[1, 2, 3, 4], [-1, -2, -3, -4]]', %q{
- def test(a, b = 2, c:, d: 4) = [a, b, c, d]
- def entry = [test(1, c: 3), test(-1, -2, d: -4, c: -3)] # specify all, change kw order
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_unexpected_keyword
- assert_compiles ':error', %q{
- def test(a: 1) = a*2
- def entry
- test(z: 2)
- rescue ArgumentError
- :error
- end
-
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_pos_optional_with_maybe_too_many_args
- assert_compiles '[[1, 2, 3, 4, 5, 6], [10, 20, 30, 4, 5, 6], [10, 20, 30, 40, 50, 60]]', %q{
- def target(a = 1, b = 2, c = 3, d = 4, e = 5, f:) = [a, b, c, d, e, f]
- def test = [target(f: 6), target(10, 20, 30, f: 6), target(10, 20, 30, 40, 50, f: 60)]
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_kwarg_partial_optional
- assert_compiles '[[1, 2, 3], [1, 20, 3], [10, 2, 30]]', %q{
- def test(a: 1, b: 2, c: 3) = [a, b, c]
- def entry = [test, test(b: 20), test(c: 30, a: 10)]
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_optional_a_lot
- assert_compiles '[[1, 2, 3, 4, 5, 6], [1, 2, 3, 7, 8, 9], [2, 4, 6, 8, 10, 12]]', %q{
- def test(a: 1, b: 2, c: 3, d: 4, e: 5, f: 6) = [a, b, c, d, e, f]
- def entry = [test, test(d: 7, f: 9, e: 8), test(f: 12, e: 10, d: 8, c: 6, b: 4, a: 2)]
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_non_constant_default
- assert_compiles '[[1, 2], [10, 2]]', %q{
- def make_default = 2
- def test(a: 1, b: make_default) = [a, b]
- def entry = [test, test(a: 10)]
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_kwarg_optional_static_with_side_exit
- # verify frame reconstruction with synthesized keyword defaults is correct
- assert_compiles '[10, 2, 10]', %q{
- def callee(a: 1, b: 2)
- # use binding to force side-exit
- x = binding.local_variable_get(:a)
- [a, b, x]
- end
-
- def entry
- callee(a: 10) # b should get default value
- end
-
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_all_arg_types
- assert_compiles '[:req, :opt, :post, :kwr, :kwo, true]', %q{
- def test(a, b = :opt, c, d:, e: :kwo) = [a, b, c, d, e, block_given?]
- def entry = test(:req, :post, d: :kwr) {}
- entry
- entry
- }, call_threshold: 2
- end
-
- def test_send_ccall_variadic_with_different_receiver_classes
- assert_compiles '[true, true]', %q{
- def test(obj) = obj.start_with?("a")
- [test("abc"), test(:abc)]
- }, call_threshold: 2
- end
-
- def test_forwardable_iseq
- assert_compiles '1', %q{
- def test(...) = 1
- test
- }
- end
-
- def test_sendforward
- assert_compiles '[1, 2]', %q{
- def callee(a, b) = [a, b]
- def test(...) = callee(...)
- test(1, 2)
- }, insns: [:sendforward]
- end
-
- def test_iseq_with_optional_arguments
- assert_compiles '[[1, 2], [3, 4]]', %q{
- def test(a, b = 2) = [a, b]
- [test(1), test(3, 4)]
- }
- end
-
- def test_invokesuper
- assert_compiles '[6, 60]', %q{
- class Foo
- def foo(a) = a + 1
- def bar(a) = a + 10
- end
-
- class Bar < Foo
- def foo(a) = super(a) + 2
- def bar(a) = super + 20
- end
-
- bar = Bar.new
- [bar.foo(3), bar.bar(30)]
- }
- end
-
- def test_invokesuper_with_local_written_by_blockiseq
- # Using `assert_runs` because we don't compile invokeblock yet
- assert_runs '3', %q{
- class Foo
- def test
- yield
- end
- end
-
- class Bar < Foo
- def test
- a = 1
- super do
- a += 2
- end
- a
- end
- end
-
- Bar.new.test
- }
- end
-
- def test_invokesuper_to_iseq
- assert_compiles '["B", "A"]', %q{
- class A
- def foo
- "A"
- end
- end
-
- class B < A
- def foo
- ["B", super]
- end
- end
-
- def test
- B.new.foo
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_args
- assert_compiles '["B", 11]', %q{
- class A
- def foo(x)
- x * 2
- end
- end
-
- class B < A
- def foo(x)
- ["B", super(x) + 1]
- end
- end
-
- def test
- B.new.foo(5)
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test super with explicit args when callee has rest parameter.
- # This should fall back to dynamic dispatch since we can't handle rest params yet.
- def test_invokesuper_with_args_to_rest_param
- assert_compiles '["B", "a", ["b", "c"]]', %q{
- class A
- def foo(x, *rest)
- [x, rest]
- end
- end
-
- class B < A
- def foo(x, y, z)
- ["B", *super(x, y, z)]
- end
- end
-
- def test
- B.new.foo("a", "b", "c")
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_block
- assert_compiles '["B", "from_block"]', %q{
- class A
- def foo
- block_given? ? yield : "no_block"
- end
- end
-
- class B < A
- def foo
- ["B", super { "from_block" }]
- end
- end
-
- def test
- B.new.foo
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_to_cfunc_no_args
- assert_compiles '["MyString", 3]', %q{
- class MyString < String
- def length
- ["MyString", super]
- end
- end
-
- def test
- MyString.new("abc").length
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_to_cfunc_simple_args
- assert_compiles '["MyString", true]', %q{
- class MyString < String
- def include?(other)
- ["MyString", super(other)]
- end
- end
-
- def test
- MyString.new("abc").include?("bc")
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
-
- def test_invokesuper_to_cfunc_with_optional_arg
- assert_compiles '["MyString", 6]', %q{
- class MyString < String
- def byteindex(needle, offset = 0)
- ["MyString", super(needle, offset)]
- end
- end
-
- def test
- MyString.new("hello world").byteindex("world")
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_to_cfunc_varargs
- assert_compiles '["MyString", true]', %q{
- class MyString < String
- def end_with?(str)
- ["MyString", super(str)]
- end
- end
-
- def test
- MyString.new("abc").end_with?("bc")
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_multilevel
- assert_compiles '["C", ["B", "A"]]', %q{
- class A
- def foo
- "A"
- end
- end
-
- class B < A
- def foo
- ["B", super]
- end
- end
-
- class C < B
- def foo
- ["C", super]
- end
- end
-
- def test
- C.new.foo
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test implicit block forwarding - super without explicit block should forward caller's block
- # Note: We call test twice to ensure ZJIT compiles it before the final call that we check
- def test_invokesuper_forwards_block_implicitly
- assert_compiles '["B", "forwarded_block"]', %q{
- class A
- def foo
- block_given? ? yield : "no_block"
- end
- end
-
- class B < A
- def foo
- ["B", super] # should forward the block from caller
- end
- end
-
- def test
- B.new.foo { "forwarded_block" }
- end
-
- test # profile invokesuper
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test implicit block forwarding with explicit arguments
- def test_invokesuper_forwards_block_implicitly_with_args
- assert_compiles '["B", ["arg_value", "forwarded"]]', %q{
- class A
- def foo(x)
- [x, (block_given? ? yield : "no_block")]
- end
- end
-
- class B < A
- def foo(x)
- ["B", super(x)] # explicit args, but block should still be forwarded
- end
- end
-
- def test
- B.new.foo("arg_value") { "forwarded" }
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test implicit block forwarding when no block is given (should not fail)
- def test_invokesuper_forwards_block_implicitly_no_block_given
- assert_compiles '["B", "no_block"]', %q{
- class A
- def foo
- block_given? ? yield : "no_block"
- end
- end
-
- class B < A
- def foo
- ["B", super] # no block given by caller
- end
- end
-
- def test
- B.new.foo # called without a block
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test implicit block forwarding through multiple inheritance levels
- def test_invokesuper_forwards_block_implicitly_multilevel
- assert_compiles '["C", ["B", "deep_block"]]', %q{
- class A
- def foo
- block_given? ? yield : "no_block"
- end
- end
-
- class B < A
- def foo
- ["B", super] # forwards block to A
- end
- end
-
- class C < B
- def foo
- ["C", super] # forwards block to B, which forwards to A
- end
- end
-
- def test
- C.new.foo { "deep_block" }
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test implicit block forwarding with block parameter syntax
- def test_invokesuper_forwards_block_param
- assert_compiles '["B", "block_param_forwarded"]', %q{
- class A
- def foo
- block_given? ? yield : "no_block"
- end
- end
-
- class B < A
- def foo(&block)
- ["B", super] # should forward &block implicitly
- end
- end
-
- def test
- B.new.foo { "block_param_forwarded" }
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_blockarg
- assert_compiles '["B", "different block"]', %q{
- class A
- def foo
- block_given? ? yield : "no block"
- end
- end
-
- class B < A
- def foo(&blk)
- other_block = proc { "different block" }
- ["B", super(&other_block)]
- end
- end
-
- def test
- B.new.foo { "passed block" }
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_symbol_to_proc
- assert_compiles '["B", [3, 5, 7]]', %q{
- class A
- def foo(items, &blk)
- items.map(&blk)
- end
- end
-
- class B < A
- def foo(items)
- ["B", super(items, &:succ)]
- end
- end
-
- def test
- B.new.foo([2, 4, 6])
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_splat
- assert_compiles '["B", 6]', %q{
- class A
- def foo(a, b, c)
- a + b + c
- end
- end
-
- class B < A
- def foo(*args)
- ["B", super(*args)]
- end
- end
-
- def test
- B.new.foo(1, 2, 3)
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_kwargs
- assert_compiles '["B", "x=1, y=2"]', %q{
- class A
- def foo(x:, y:)
- "x=#{x}, y=#{y}"
- end
- end
-
- class B < A
- def foo(x:, y:)
- ["B", super(x: x, y: y)]
- end
- end
-
- def test
- B.new.foo(x: 1, y: 2)
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_kw_splat
- assert_compiles '["B", "x=1, y=2"]', %q{
- class A
- def foo(x:, y:)
- "x=#{x}, y=#{y}"
- end
- end
-
- class B < A
- def foo(**kwargs)
- ["B", super(**kwargs)]
- end
- end
-
- def test
- B.new.foo(x: 1, y: 2)
- end
-
- test # profile
- test # compile + run compiled code
- }, call_threshold: 2
- end
-
- # Test that including a module after compilation correctly changes the super target.
- # The included module's method should be called, not the original super target.
- def test_invokesuper_with_include
- assert_compiles '["B", "M"]', %q{
- class A
- def foo
- "A"
- end
- end
-
- class B < A
- def foo
- ["B", super]
- end
- end
-
- def test
- B.new.foo
- end
-
- test # profile invokesuper (super -> A#foo)
- test # compile with super -> A#foo
-
- # Now include a module in B that defines foo - super should go to M#foo instead
- module M
- def foo
- "M"
- end
- end
- B.include(M)
-
- test # should call M#foo, not A#foo
- }, call_threshold: 2
- end
-
- # Test that prepending a module after compilation correctly changes the super target.
- # The prepended module's method should be called, not the original super target.
- def test_invokesuper_with_prepend
- assert_compiles '["B", "M"]', %q{
- class A
- def foo
- "A"
- end
- end
-
- class B < A
- def foo
- ["B", super]
- end
- end
-
- def test
- B.new.foo
- end
-
- test # profile invokesuper (super -> A#foo)
- test # compile with super -> A#foo
-
- # Now prepend a module that defines foo - super should go to M#foo instead
- module M
- def foo
- "M"
- end
- end
- A.prepend(M)
-
- test # should call M#foo, not A#foo
- }, call_threshold: 2
- end
-
- # Test super with positional and keyword arguments (pattern from chunky_png)
- def test_invokesuper_with_keyword_args
- assert_compiles '{content: "image data"}', %q{
- class A
- def foo(attributes = {})
- @attributes = attributes
- end
- end
-
- class B < A
- def foo(content = '')
- super(content: content)
- end
- end
-
- def test
- B.new.foo("image data")
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_invokesuper_with_optional_keyword_args
- assert_compiles '[1, 2, 3]', %q{
- class Parent
- def foo(a, b: 2, c: 3) = [a, b, c]
- end
-
- class Child < Parent
- def foo(a) = super(a)
- end
-
- def test = Child.new.foo(1)
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_invokesuperforward
- assert_compiles '[1, 2, 3]', %q{
- class A
- def foo(a,b,c) = [a,b,c]
- end
-
- class B < A
- def foo(...) = super
- end
-
- def test
- B.new.foo(1, 2, 3)
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_invokesuperforward_with_args_kwargs_and_block
- assert_compiles '[[1, 2], {x: 3}, 4]', %q{
- class A
- def foo(*args, **kwargs, &block)
- [args, kwargs, block&.call]
- end
- end
-
- class B < A
- def foo(...) = super
- end
-
- def test
- B.new.foo(1, 2, x: 3) { 4 }
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default
- assert_compiles '[[2, 4, 16], [10, 4, 16], [2, 20, 16], [2, 4, 30], [10, 20, 30]]', %q{
- def dbl(x = 1) = x * 2
-
- def foo(a: dbl, b: dbl(2), c: dbl(2 ** 3))
- [a, b, c]
- end
-
- def test
- [
- foo,
- foo(a: 10),
- foo(b: 20),
- foo(c: 30),
- foo(a: 10, b: 20, c: 30)
- ]
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default_not_evaluated_when_provided
- assert_compiles '[1, 2, 3]', %q{
- def foo(a: raise, b: raise, c: raise)
- [a, b, c]
- end
-
- def test
- foo(a: 1, b: 2, c: 3)
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default_evaluated_when_not_provided
- assert_compiles '["a", "b", "c"]', %q{
- def raise_a = raise "a"
- def raise_b = raise "b"
- def raise_c = raise "c"
-
- def foo(a: raise_a, b: raise_b, c: raise_c)
- [a, b, c]
- end
-
- def test_a
- foo(b: 2, c: 3)
- rescue RuntimeError => e
- e.message
- end
-
- def test_b
- foo(a: 1, c: 3)
- rescue RuntimeError => e
- e.message
- end
-
- def test_c
- foo(a: 1, b: 2)
- rescue RuntimeError => e
- e.message
- end
-
- def test
- [test_a, test_b, test_c]
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default_jit_to_jit
- # Test that kw_bits passing works correctly in JIT-to-JIT calls
- assert_compiles '[2, 4, 6]', %q{
- def make_default(x) = x * 2
-
- def callee(a: make_default(1), b: make_default(2), c: make_default(3))
- [a, b, c]
- end
-
- def caller_method
- callee
- end
-
- # Warm up callee first so it gets JITted
- callee
- callee
-
- # Now warm up caller - this creates JIT-to-JIT call
- caller_method
- caller_method
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default_side_exit
- # Verify frame reconstruction includes correct values for non-constant defaults
- assert_compiles '[10, 2, 30]', %q{
- def make_b = 2
-
- def callee(a: 1, b: make_b, c: 3)
- x = binding.local_variable_get(:a)
- y = binding.local_variable_get(:b)
- z = binding.local_variable_get(:c)
- [x, y, z]
- end
-
- def test
- callee(a: 10, c: 30)
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_non_constant_keyword_default_evaluation_order
- # Verify defaults are evaluated left-to-right and only when not provided
- assert_compiles '[["a", "b", "c"], ["b", "c"], ["a", "c"], ["a", "b"]]', %q{
- def log(x)
- $order << x
- x
- end
-
- def foo(a: log("a"), b: log("b"), c: log("c"))
- [a, b, c]
- end
-
- def test
- results = []
-
- $order = []
- foo
- results << $order.dup
-
- $order = []
- foo(a: "A")
- results << $order.dup
-
- $order = []
- foo(b: "B")
- results << $order.dup
-
- $order = []
- foo(c: "C")
- results << $order.dup
-
- results
- end
-
- test
- test
- }, call_threshold: 2
- end
-
- def test_send_with_too_many_non_constant_keyword_defaults
- assert_compiles '35', %q{
- def many_kwargs( k1: 1, k2: 2, k3: 3, k4: 4, k5: 5, k6: 6, k7: 7, k8: 8, k9: 9, k10: 10, k11: 11, k12: 12, k13: 13, k14: 14, k15: 15, k16: 16, k17: 17, k18: 18, k19: 19, k20: 20, k21: 21, k22: 22, k23: 23, k24: 24, k25: 25, k26: 26, k27: 27, k28: 28, k29: 29, k30: 30, k31: 31, k32: 32, k33: 33, k34: k33 + 1) = k1 + k34
- def t = many_kwargs
- t
- t
- }, call_threshold: 2
- end
-
- def test_invokebuiltin
- # Not using assert_compiles due to register spill
- assert_runs '["."]', %q{
- def test = Dir.glob(".")
- test
- }
- end
-
- def test_invokebuiltin_delegate
- assert_compiles '[[], true]', %q{
- def test = [].clone(freeze: true)
- r = test
- [r, r.frozen?]
- }
- end
-
- def test_opt_plus_const
- assert_compiles '3', %q{
- def test = 1 + 2
- test # profile opt_plus
- test
- }, call_threshold: 2
- end
-
- def test_opt_plus_fixnum
- assert_compiles '3', %q{
- def test(a, b) = a + b
- test(0, 1) # profile opt_plus
- test(1, 2)
- }, call_threshold: 2
- end
-
- def test_opt_plus_chain
- assert_compiles '6', %q{
- def test(a, b, c) = a + b + c
- test(0, 1, 2) # profile opt_plus
- test(1, 2, 3)
- }, call_threshold: 2
- end
-
- def test_opt_plus_left_imm
- assert_compiles '3', %q{
- def test(a) = 1 + a
- test(1) # profile opt_plus
- test(2)
- }, call_threshold: 2
- end
-
- def test_opt_plus_type_guard_exit
- assert_compiles '[3, 3.0]', %q{
- def test(a) = 1 + a
- test(1) # profile opt_plus
- [test(2), test(2.0)]
- }, call_threshold: 2
- end
-
- def test_opt_plus_type_guard_exit_with_locals
- assert_compiles '[6, 6.0]', %q{
- def test(a)
- local = 3
- 1 + a + local
- end
- test(1) # profile opt_plus
- [test(2), test(2.0)]
- }, call_threshold: 2
- end
-
- def test_opt_plus_type_guard_nested_exit
- assert_compiles '[4, 4.0]', %q{
- def side_exit(n) = 1 + n
- def jit_frame(n) = 1 + side_exit(n)
- def entry(n) = jit_frame(n)
- entry(2) # profile send
- [entry(2), entry(2.0)]
- }, call_threshold: 2
- end
-
- def test_opt_plus_type_guard_nested_exit_with_locals
- assert_compiles '[9, 9.0]', %q{
- def side_exit(n)
- local = 2
- 1 + n + local
- end
- def jit_frame(n)
- local = 3
- 1 + side_exit(n) + local
- end
- def entry(n) = jit_frame(n)
- entry(2) # profile send
- [entry(2), entry(2.0)]
- }, call_threshold: 2
- end
-
- # Test argument ordering
- def test_opt_minus
- assert_compiles '2', %q{
- def test(a, b) = a - b
- test(2, 1) # profile opt_minus
- test(6, 4)
- }, call_threshold: 2
- end
-
- def test_opt_mult
- assert_compiles '6', %q{
- def test(a, b) = a * b
- test(1, 2) # profile opt_mult
- test(2, 3)
- }, call_threshold: 2
- end
-
- def test_opt_mult_overflow
- assert_compiles '[6, -6, 9671406556917033397649408, -9671406556917033397649408, 21267647932558653966460912964485513216]', %q{
- def test(a, b)
- a * b
- end
- test(1, 1) # profile opt_mult
-
- r1 = test(2, 3)
- r2 = test(2, -3)
- r3 = test(2 << 40, 2 << 41)
- r4 = test(2 << 40, -2 << 41)
- r5 = test(1 << 62, 1 << 62)
-
- [r1, r2, r3, r4, r5]
- }, call_threshold: 2
- end
-
- def test_opt_eq
- assert_compiles '[true, false]', %q{
- def test(a, b) = a == b
- test(0, 2) # profile opt_eq
- [test(1, 1), test(0, 1)]
- }, insns: [:opt_eq], call_threshold: 2
- end
-
- def test_opt_eq_with_minus_one
- assert_compiles '[false, true]', %q{
- def test(a) = a == -1
- test(1) # profile opt_eq
- [test(0), test(-1)]
- }, insns: [:opt_eq], call_threshold: 2
- end
-
- def test_opt_neq_dynamic
- # TODO(max): Don't split this test; instead, run all tests with and without
- # profiling.
- assert_compiles '[false, true]', %q{
- def test(a, b) = a != b
- test(0, 2) # profile opt_neq
- [test(1, 1), test(0, 1)]
- }, insns: [:opt_neq], call_threshold: 1
- end
-
- def test_opt_neq_fixnum
- assert_compiles '[false, true]', %q{
- def test(a, b) = a != b
- test(0, 2) # profile opt_neq
- [test(1, 1), test(0, 1)]
- }, call_threshold: 2
- end
-
- def test_opt_lt
- assert_compiles '[true, false, false]', %q{
- def test(a, b) = a < b
- test(2, 3) # profile opt_lt
- [test(0, 1), test(0, 0), test(1, 0)]
- }, insns: [:opt_lt], call_threshold: 2
- end
-
- def test_opt_lt_with_literal_lhs
- assert_compiles '[false, false, true]', %q{
- def test(n) = 2 < n
- test(2) # profile opt_lt
- [test(1), test(2), test(3)]
- }, insns: [:opt_lt], call_threshold: 2
- end
-
- def test_opt_le
- assert_compiles '[true, true, false]', %q{
- def test(a, b) = a <= b
- test(2, 3) # profile opt_le
- [test(0, 1), test(0, 0), test(1, 0)]
- }, insns: [:opt_le], call_threshold: 2
- end
-
- def test_opt_gt
- assert_compiles '[false, false, true]', %q{
- def test(a, b) = a > b
- test(2, 3) # profile opt_gt
- [test(0, 1), test(0, 0), test(1, 0)]
- }, 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_succ
- assert_compiles('[0, "B"]', <<~RUBY, insns: [:opt_succ])
- def test(obj) = obj.succ
- return test(-1), test("A")
- RUBY
- end
-
- def test_opt_and
- assert_compiles('[1, [3, 2, 1]]', <<~RUBY, insns: [:opt_and])
- def test(x, y) = x & y
- return test(0b1101, 3), test([3, 2, 1, 4], [8, 1, 2, 3])
- RUBY
- end
-
- def test_opt_or
- assert_compiles('[11, [3, 2, 1]]', <<~RUBY, insns: [:opt_or])
- def test(x, y) = x | y
- return test(0b1000, 3), test([3, 2, 1], [1, 2, 3])
- RUBY
- end
-
- def test_fixnum_and
- assert_compiles '[1, 2, 4]', %q{
- def test(a, b) = a & b
- [
- test(5, 3),
- test(0b011, 0b110),
- test(-0b011, 0b110)
- ]
- }, call_threshold: 2, insns: [:opt_and]
- end
-
- def test_fixnum_and_side_exit
- assert_compiles '[2, 2, false]', %q{
- def test(a, b) = a & b
- [
- test(2, 2),
- test(0b011, 0b110),
- test(true, false)
- ]
- }, call_threshold: 2, insns: [:opt_and]
- end
-
- def test_fixnum_or
- assert_compiles '[7, 3, -3]', %q{
- def test(a, b) = a | b
- [
- test(5, 3),
- test(1, 2),
- test(1, -4)
- ]
- }, call_threshold: 2, insns: [:opt_or]
- end
-
- def test_fixnum_or_side_exit
- assert_compiles '[3, 2, true]', %q{
- def test(a, b) = a | b
- [
- test(1, 2),
- test(2, 2),
- test(true, false)
- ]
- }, call_threshold: 2, insns: [:opt_or]
- end
-
- def test_fixnum_xor
- assert_compiles '[6, -8, 3]', %q{
- def test(a, b) = a ^ b
- [
- test(5, 3),
- test(-5, 3),
- test(1, 2)
- ]
- }, call_threshold: 2
- end
-
- def test_fixnum_xor_side_exit
- assert_compiles '[6, 6, true]', %q{
- def test(a, b) = a ^ b
- [
- test(5, 3),
- test(5, 3),
- test(true, false)
- ]
- }, call_threshold: 2
- end
-
- def test_fixnum_mul
- assert_compiles '12', %q{
- C = 3
- def test(n) = C * n
- test(4)
- test(4)
- test(4)
- }, call_threshold: 2, insns: [:opt_mult]
- end
-
- def test_fixnum_div
- assert_compiles '12', %q{
- C = 48
- def test(n) = C / n
- test(4)
- test(4)
- }, call_threshold: 2, insns: [:opt_div]
- end
-
- def test_fixnum_floor
- assert_compiles '0', %q{
- C = 3
- def test(n) = C / n
- test(4)
- test(4)
- }, call_threshold: 2, insns: [:opt_div]
- end
-
- def test_fixnum_div_zero
- assert_runs '"divided by 0"', %q{
- def test(n)
- n / 0
- rescue ZeroDivisionError => e
- e.message
- end
-
- test(0)
- test(0)
- }, call_threshold: 2, insns: [:opt_div]
- end
-
- def test_opt_not
- assert_compiles('[true, true, false]', <<~RUBY, insns: [:opt_not])
- def test(obj) = !obj
- return test(nil), test(false), test(0)
- RUBY
- end
-
- def test_opt_regexpmatch2
- assert_compiles('[1, nil]', <<~RUBY, insns: [:opt_regexpmatch2])
- def test(haystack) = /needle/ =~ haystack
- return test("kneedle"), test("")
- RUBY
- end
-
- def test_opt_ge
- assert_compiles '[false, true, true]', %q{
- def test(a, b) = a >= b
- test(2, 3) # profile opt_ge
- [test(0, 1), test(0, 0), test(1, 0)]
- }, insns: [:opt_ge], call_threshold: 2
- end
-
- def test_opt_new_does_not_push_frame
- assert_compiles 'nil', %q{
- class Foo
- attr_reader :backtrace
-
- def initialize
- @backtrace = caller
- end
- end
- def test = Foo.new
-
- foo = test
- foo.backtrace.find do |frame|
- frame.include?('Class#new')
- end
- }, insns: [:opt_new]
- end
-
- def test_opt_new_with_redefined
- assert_compiles '"foo"', %q{
- class Foo
- def self.new = "foo"
-
- def initialize = raise("unreachable")
- end
- def test = Foo.new
-
- test
- }, insns: [:opt_new]
- end
-
- def test_opt_new_invalidate_new
- assert_compiles '["Foo", "foo"]', %q{
- class Foo; end
- def test = Foo.new
- test; test
- result = [test.class.name]
- def Foo.new = "foo"
- result << test
- result
- }, insns: [:opt_new], call_threshold: 2
- end
-
def test_opt_new_with_custom_allocator
assert_compiles '"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"', %q{
require "digest"
@@ -2171,1208 +164,6 @@ class TestZJIT < Test::Unit::TestCase
}, insns: [:opt_new], call_threshold: 2
end
- def test_opt_newarray_send_include_p
- assert_compiles '[true, false]', %q{
- def test(x)
- [:y, 1, Object.new].include?(x)
- end
- [test(1), test("n")]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_include_p_redefined
- assert_compiles '[:true, :false]', %q{
- class Array
- alias_method :old_include?, :include?
- def include?(x)
- old_include?(x) ? :true : :false
- end
- end
-
- def test(x)
- [:y, 1, Object.new].include?(x)
- end
- [test(1), test("n")]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_duparray_send_include_p
- assert_compiles '[true, false]', %q{
- def test(x)
- [:y, 1].include?(x)
- end
- [test(1), test("n")]
- }, insns: [:opt_duparray_send], call_threshold: 1
- end
-
- def test_opt_duparray_send_include_p_redefined
- assert_compiles '[:true, :false]', %q{
- class Array
- alias_method :old_include?, :include?
- def include?(x)
- old_include?(x) ? :true : :false
- end
- end
-
- def test(x)
- [:y, 1].include?(x)
- end
- [test(1), test("n")]
- }, insns: [:opt_duparray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_pack_buffer
- assert_compiles '["ABC", "ABC", "ABC", "ABC"]', %q{
- def test(num, buffer)
- [num].pack('C', buffer:)
- end
- buf = ""
- [test(65, buf), test(66, buf), test(67, buf), buf]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_pack_buffer_redefined
- assert_compiles '["b", "A"]', %q{
- class Array
- alias_method :old_pack, :pack
- def pack(fmt, buffer: nil)
- old_pack(fmt, buffer: buffer)
- "b"
- end
- end
-
- def test(num, buffer)
- [num].pack('C', buffer:)
- end
- buf = ""
- [test(65, buf), buf]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_hash
- assert_compiles 'Integer', %q{
- def test(x)
- [1, 2, x].hash
- end
- test(20).class
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_hash_redefined
- assert_compiles '42', %q{
- Array.class_eval { def hash = 42 }
-
- def test(x)
- [1, 2, x].hash
- end
- test(20)
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_max
- assert_compiles '[20, 40]', %q{
- def test(a,b) = [a,b].max
- [test(10, 20), test(40, 30)]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_opt_newarray_send_max_redefined
- assert_compiles '[60, 90]', %q{
- class Array
- alias_method :old_max, :max
- def max
- old_max * 2
- end
- end
-
- def test(a,b) = [a,b].max
- [test(15, 30), test(45, 35)]
- }, insns: [:opt_newarray_send], call_threshold: 1
- end
-
- def test_new_hash_empty
- assert_compiles '{}', %q{
- def test = {}
- test
- }, insns: [:newhash]
- end
-
- def test_new_hash_nonempty
- assert_compiles '{"key" => "value", 42 => 100}', %q{
- def test
- key = "key"
- value = "value"
- num = 42
- result = 100
- {key => value, num => result}
- end
- test
- }, insns: [:newhash]
- end
-
- def test_new_hash_single_key_value
- assert_compiles '{"key" => "value"}', %q{
- def test = {"key" => "value"}
- test
- }, insns: [:newhash]
- end
-
- def test_new_hash_with_computation
- assert_compiles '{"sum" => 5, "product" => 6}', %q{
- def test(a, b)
- {"sum" => a + b, "product" => a * b}
- end
- test(2, 3)
- }, insns: [:newhash]
- end
-
- def test_new_hash_with_user_defined_hash_method
- assert_runs 'true', %q{
- class CustomKey
- attr_reader :val
-
- def initialize(val)
- @val = val
- end
-
- def hash
- @val.hash
- end
-
- def eql?(other)
- other.is_a?(CustomKey) && @val == other.val
- end
- end
-
- def test
- key = CustomKey.new("key")
- hash = {key => "value"}
- hash[key] == "value"
- end
- test
- }
- end
-
- def test_new_hash_with_user_hash_method_exception
- assert_runs 'RuntimeError', %q{
- class BadKey
- def hash
- raise "Hash method failed!"
- end
- end
-
- def test
- key = BadKey.new
- {key => "value"}
- end
-
- begin
- test
- rescue => e
- e.class
- end
- }
- end
-
- def test_new_hash_with_user_eql_method_exception
- assert_runs 'RuntimeError', %q{
- class BadKey
- def hash
- 42
- end
-
- def eql?(other)
- raise "Eql method failed!"
- end
- end
-
- def test
- key1 = BadKey.new
- key2 = BadKey.new
- {key1 => "value1", key2 => "value2"}
- end
-
- begin
- test
- rescue => e
- e.class
- end
- }
- end
-
- def test_opt_hash_freeze
- assert_compiles "[{}, 5]", %q{
- def test = {}.freeze
- result = [test]
- class Hash
- def freeze = 5
- end
- result << test
- }, insns: [:opt_hash_freeze], call_threshold: 1
- end
-
- def test_opt_hash_freeze_rewritten
- assert_compiles "5", %q{
- class Hash
- def freeze = 5
- end
- def test = {}.freeze
- test
- }, insns: [:opt_hash_freeze], call_threshold: 1
- end
-
- def test_opt_aset_hash
- assert_compiles '42', %q{
- def test(h, k, v)
- h[k] = v
- end
- h = {}
- test(h, :key, 42)
- test(h, :key, 42)
- h[:key]
- }, call_threshold: 2, insns: [:opt_aset]
- end
-
- def test_opt_aset_hash_returns_value
- assert_compiles '100', %q{
- def test(h, k, v)
- h[k] = v
- end
- test({}, :key, 100)
- test({}, :key, 100)
- }, call_threshold: 2
- end
-
- def test_opt_aset_hash_string_key
- assert_compiles '"bar"', %q{
- def test(h, k, v)
- h[k] = v
- end
- h = {}
- test(h, "foo", "bar")
- test(h, "foo", "bar")
- h["foo"]
- }, call_threshold: 2
- end
-
- def test_opt_aset_hash_subclass
- assert_compiles '42', %q{
- class MyHash < Hash; end
- def test(h, k, v)
- h[k] = v
- end
- h = MyHash.new
- test(h, :key, 42)
- test(h, :key, 42)
- h[:key]
- }, call_threshold: 2
- end
-
- def test_opt_aset_hash_too_few_args
- assert_compiles '"ArgumentError"', %q{
- def test(h)
- h.[]= 123
- rescue ArgumentError
- "ArgumentError"
- end
- test({})
- test({})
- }, call_threshold: 2
- end
-
- def test_opt_aset_hash_too_many_args
- assert_compiles '"ArgumentError"', %q{
- def test(h)
- h[:a, :b] = :c
- rescue ArgumentError
- "ArgumentError"
- end
- test({})
- test({})
- }, call_threshold: 2
- end
-
- def test_opt_ary_freeze
- assert_compiles "[[], 5]", %q{
- def test = [].freeze
- result = [test]
- class Array
- def freeze = 5
- end
- result << test
- }, insns: [:opt_ary_freeze], call_threshold: 1
- end
-
- def test_opt_ary_freeze_rewritten
- assert_compiles "5", %q{
- class Array
- def freeze = 5
- end
- def test = [].freeze
- test
- }, insns: [:opt_ary_freeze], call_threshold: 1
- end
-
- def test_opt_str_freeze
- assert_compiles "[\"\", 5]", %q{
- def test = ''.freeze
- result = [test]
- class String
- def freeze = 5
- end
- result << test
- }, insns: [:opt_str_freeze], call_threshold: 1
- end
-
- def test_opt_str_freeze_rewritten
- assert_compiles "5", %q{
- class String
- def freeze = 5
- end
- def test = ''.freeze
- test
- }, insns: [:opt_str_freeze], call_threshold: 1
- end
-
- def test_opt_str_uminus
- assert_compiles "[\"\", 5]", %q{
- def test = -''
- result = [test]
- class String
- def -@ = 5
- end
- result << test
- }, insns: [:opt_str_uminus], call_threshold: 1
- end
-
- def test_opt_str_uminus_rewritten
- assert_compiles "5", %q{
- class String
- def -@ = 5
- end
- def test = -''
- test
- }, insns: [:opt_str_uminus], call_threshold: 1
- end
-
- def test_new_array_empty
- assert_compiles '[]', %q{
- def test = []
- test
- }, insns: [:newarray]
- end
-
- def test_new_array_nonempty
- assert_compiles '[5]', %q{
- def a = 5
- def test = [a]
- test
- }
- end
-
- def test_new_array_order
- assert_compiles '[3, 2, 1]', %q{
- def a = 3
- def b = 2
- def c = 1
- def test = [a, b, c]
- test
- }
- end
-
- def test_array_dup
- assert_compiles '[1, 2, 3]', %q{
- def test = [1,2,3]
- test
- }
- end
-
- def test_array_fixnum_aref
- assert_compiles '3', %q{
- def test(x) = [1,2,3][x]
- test(2)
- test(2)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_array_fixnum_aref_negative_index
- assert_compiles '3', %q{
- def test(x) = [1,2,3][x]
- test(-1)
- test(-1)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_array_fixnum_aref_out_of_bounds_positive
- assert_compiles 'nil', %q{
- def test(x) = [1,2,3][x]
- test(10)
- test(10)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_array_fixnum_aref_out_of_bounds_negative
- assert_compiles 'nil', %q{
- def test(x) = [1,2,3][x]
- test(-10)
- test(-10)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_array_fixnum_aref_array_subclass
- assert_compiles '3', %q{
- class MyArray < Array; end
- def test(arr, idx) = arr[idx]
- arr = MyArray[1,2,3]
- test(arr, 2)
- arr = MyArray[1,2,3]
- test(arr, 2)
- }, call_threshold: 2, insns: [:opt_aref]
- end
-
- def test_array_aref_non_fixnum_index
- assert_compiles 'TypeError', %q{
- def test(arr, idx) = arr[idx]
- test([1,2,3], 1)
- test([1,2,3], 1)
- begin
- test([1,2,3], "1")
- rescue => e
- e.class
- end
- }, call_threshold: 2
- end
-
- def test_array_fixnum_aset
- assert_compiles '[1, 2, 7]', %q{
- def test(arr, idx)
- arr[idx] = 7
- end
- arr = [1,2,3]
- test(arr, 2)
- arr = [1,2,3]
- test(arr, 2)
- arr
- }, call_threshold: 2, insns: [:opt_aset]
- end
-
- def test_array_fixnum_aset_returns_value
- assert_compiles '7', %q{
- def test(arr, idx)
- arr[idx] = 7
- end
- test([1,2,3], 2)
- test([1,2,3], 2)
- }, call_threshold: 2, insns: [:opt_aset]
- end
-
- def test_array_fixnum_aset_out_of_bounds
- assert_compiles '[1, 2, 3, nil, nil, 7]', %q{
- def test(arr)
- arr[5] = 7
- end
- arr = [1,2,3]
- test(arr)
- arr = [1,2,3]
- test(arr)
- arr
- }, call_threshold: 2
- end
-
- def test_array_fixnum_aset_negative_index
- assert_compiles '[1, 2, 7]', %q{
- def test(arr)
- arr[-1] = 7
- end
- arr = [1,2,3]
- test(arr)
- arr = [1,2,3]
- test(arr)
- arr
- }, call_threshold: 2
- end
-
- def test_array_fixnum_aset_shared
- assert_compiles '[10, 999, -1, -2]', %q{
- def test(arr, idx, val)
- arr[idx] = val
- end
- arr = (0..50).to_a
- test(arr, 0, -1)
- test(arr, 1, -2)
- shared = arr[10, 20]
- test(shared, 0, 999)
- [arr[10], shared[0], arr[0], arr[1]]
- }, call_threshold: 2
- end
-
- def test_array_fixnum_aset_frozen
- assert_compiles 'FrozenError', %q{
- def test(arr, idx, val)
- arr[idx] = val
- end
- arr = [1,2,3]
- test(arr, 1, 9)
- test(arr, 1, 9)
- arr.freeze
- begin
- test(arr, 1, 9)
- rescue => e
- e.class
- end
- }, call_threshold: 2
- end
-
- def test_array_fixnum_aset_array_subclass
- assert_compiles '7', %q{
- class MyArray < Array; end
- def test(arr, idx)
- arr[idx] = 7
- end
- arr = MyArray.new
- test(arr, 0)
- arr = MyArray.new
- test(arr, 0)
- arr[0]
- }, call_threshold: 2, insns: [:opt_aset]
- end
-
- def test_array_aset_non_fixnum_index
- assert_compiles 'TypeError', %q{
- def test(arr, idx)
- arr[idx] = 7
- end
- test([1,2,3], 0)
- test([1,2,3], 0)
- begin
- test([1,2,3], "0")
- rescue => e
- e.class
- end
- }, call_threshold: 2
- end
-
- def test_empty_array_pop
- assert_compiles 'nil', %q{
- def test(arr) = arr.pop
- test([])
- test([])
- }, call_threshold: 2
- end
-
- def test_array_pop_no_arg
- assert_compiles '42', %q{
- def test(arr) = arr.pop
- test([32, 33, 42])
- test([32, 33, 42])
- }, call_threshold: 2
- end
-
- def test_array_pop_arg
- assert_compiles '[33, 42]', %q{
- def test(arr) = arr.pop(2)
- test([32, 33, 42])
- test([32, 33, 42])
- }, call_threshold: 2
- end
-
- def test_new_range_inclusive
- assert_compiles '1..5', %q{
- def test(a, b) = a..b
- test(1, 5)
- }
- end
-
- def test_new_range_exclusive
- assert_compiles '1...5', %q{
- def test(a, b) = a...b
- test(1, 5)
- }
- end
-
- def test_new_range_with_literal
- assert_compiles '3..10', %q{
- def test(n) = n..10
- test(3)
- }
- end
-
- def test_new_range_fixnum_both_literals_inclusive
- assert_compiles '1..2', %q{
- def test()
- a = 2
- (1..a)
- end
- test; test
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_new_range_fixnum_both_literals_exclusive
- assert_compiles '1...2', %q{
- def test()
- a = 2
- (1...a)
- end
- test; test
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_new_range_fixnum_low_literal_inclusive
- assert_compiles '1..3', %q{
- def test(a)
- (1..a)
- end
- test(2); test(3)
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_new_range_fixnum_low_literal_exclusive
- assert_compiles '1...3', %q{
- def test(a)
- (1...a)
- end
- test(2); test(3)
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_new_range_fixnum_high_literal_inclusive
- assert_compiles '3..10', %q{
- def test(a)
- (a..10)
- end
- test(2); test(3)
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_new_range_fixnum_high_literal_exclusive
- assert_compiles '3...10', %q{
- def test(a)
- (a...10)
- end
- test(2); test(3)
- }, call_threshold: 2, insns: [:newrange]
- end
-
- def test_if
- assert_compiles '[0, nil]', %q{
- def test(n)
- if n < 5
- 0
- end
- end
- [test(3), test(7)]
- }
- end
-
- def test_if_else
- assert_compiles '[0, 1]', %q{
- def test(n)
- if n < 5
- 0
- else
- 1
- end
- end
- [test(3), test(7)]
- }
- end
-
- def test_if_else_params
- assert_compiles '[1, 20]', %q{
- def test(n, a, b)
- if n < 5
- a
- else
- b
- end
- end
- [test(3, 1, 2), test(7, 10, 20)]
- }
- end
-
- def test_if_else_nested
- assert_compiles '[3, 8, 9, 14]', %q{
- def test(a, b, c, d, e)
- if 2 < a
- if a < 4
- b
- else
- c
- end
- else
- if a < 0
- d
- else
- e
- end
- end
- end
- [
- test(-1, 1, 2, 3, 4),
- test( 0, 5, 6, 7, 8),
- test( 3, 9, 10, 11, 12),
- test( 5, 13, 14, 15, 16),
- ]
- }
- end
-
- def test_if_else_chained
- assert_compiles '[12, 11, 21]', %q{
- def test(a)
- (if 2 < a then 1 else 2 end) + (if a < 4 then 10 else 20 end)
- end
- [test(0), test(3), test(5)]
- }
- end
-
- def test_if_elsif_else
- assert_compiles '[0, 2, 1]', %q{
- def test(n)
- if n < 5
- 0
- elsif 8 < n
- 1
- else
- 2
- end
- end
- [test(3), test(7), test(9)]
- }
- end
-
- def test_ternary_operator
- assert_compiles '[1, 20]', %q{
- def test(n, a, b)
- n < 5 ? a : b
- end
- [test(3, 1, 2), test(7, 10, 20)]
- }
- end
-
- def test_ternary_operator_nested
- assert_compiles '[2, 21]', %q{
- def test(n, a, b)
- (n < 5 ? a : b) + 1
- end
- [test(3, 1, 2), test(7, 10, 20)]
- }
- end
-
- def test_while_loop
- assert_compiles '10', %q{
- def test(n)
- i = 0
- while i < n
- i = i + 1
- end
- i
- end
- test(10)
- }
- end
-
- def test_while_loop_chain
- assert_compiles '[135, 270]', %q{
- def test(n)
- i = 0
- while i < n
- i = i + 1
- end
- while i < n * 10
- i = i * 3
- end
- i
- end
- [test(5), test(10)]
- }
- end
-
- def test_while_loop_nested
- assert_compiles '[0, 4, 12]', %q{
- def test(n, m)
- i = 0
- while i < n
- j = 0
- while j < m
- j += 2
- end
- i += j
- end
- i
- end
- [test(0, 0), test(1, 3), test(10, 5)]
- }
- end
-
- def test_while_loop_if_else
- assert_compiles '[9, -1]', %q{
- def test(n)
- i = 0
- while i < n
- if n >= 10
- return -1
- else
- i = i + 1
- end
- end
- i
- end
- [test(9), test(10)]
- }
- end
-
- def test_if_while_loop
- assert_compiles '[9, 12]', %q{
- def test(n)
- i = 0
- if n < 10
- while i < n
- i += 1
- end
- else
- while i < n
- i += 3
- end
- end
- i
- end
- [test(9), test(10)]
- }
- end
-
- def test_live_reg_past_ccall
- assert_compiles '2', %q{
- def callee = 1
- def test = callee + callee
- test
- }
- end
-
- def test_method_call
- assert_compiles '12', %q{
- def callee(a, b)
- a - b
- end
-
- def test
- callee(4, 2) + 10
- end
-
- test # profile test
- test
- }, call_threshold: 2
- end
-
- def test_recursive_fact
- assert_compiles '[1, 6, 720]', %q{
- def fact(n)
- if n == 0
- return 1
- end
- return n * fact(n-1)
- end
- [fact(0), fact(3), fact(6)]
- }
- end
-
- def test_profiled_fact
- assert_compiles '[1, 6, 720]', %q{
- def fact(n)
- if n == 0
- return 1
- end
- return n * fact(n-1)
- end
- fact(1) # profile fact
- [fact(0), fact(3), fact(6)]
- }, call_threshold: 3, num_profiles: 2
- end
-
- def test_recursive_fib
- assert_compiles '[0, 2, 3]', %q{
- def fib(n)
- if n < 2
- return n
- end
- return fib(n-1) + fib(n-2)
- end
- [fib(0), fib(3), fib(4)]
- }
- end
-
- def test_profiled_fib
- assert_compiles '[0, 2, 3]', %q{
- def fib(n)
- if n < 2
- return n
- end
- return fib(n-1) + fib(n-2)
- end
- fib(3) # profile fib
- [fib(0), fib(3), fib(4)]
- }, call_threshold: 5, num_profiles: 3
- end
-
- def test_spilled_basic_block_args
- assert_compiles '55', %q{
- def test(n1, n2)
- n3 = 3
- n4 = 4
- n5 = 5
- n6 = 6
- n7 = 7
- n8 = 8
- n9 = 9
- n10 = 10
- if n1 < n2
- n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10
- end
- end
- test(1, 2)
- }
- end
-
- def test_spilled_method_args
- assert_runs '55', %q{
- def foo(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10)
- n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10
- end
-
- def test
- foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- end
-
- test
- }
-
- # TODO(Shopify/ruby#716): Support spills and change to assert_compiles
- assert_runs '1', %q{
- def a(n1,n2,n3,n4,n5,n6,n7,n8,n9) = n1+n9
- a(2,0,0,0,0,0,0,0,-1)
- }
-
- # TODO(Shopify/ruby#716): Support spills and change to assert_compiles
- assert_runs '0', %q{
- def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8
- a(1,1,1,1,1,1,1,0)
- }
-
- # TODO(Shopify/ruby#716): Support spills and change to assert_compiles
- # self param with spilled param
- assert_runs '"main"', %q{
- def a(n1,n2,n3,n4,n5,n6,n7,n8) = self
- a(1,0,0,0,0,0,0,0).to_s
- }
- end
-
- def test_spilled_param_new_arary
- # TODO(Shopify/ruby#716): Support spills and change to assert_compiles
- assert_runs '[:ok]', %q{
- def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
- a(0,0,0,0,0,0,0, :ok)
- }
- end
-
- def test_forty_param_method
- # This used to a trigger a miscomp on A64 due
- # to a memory displacement larger than 9 bits.
- # Using assert_runs again due to register spill.
- # TODO: It should be fixed by register spill support.
- assert_runs '1', %Q{
- def foo(#{'_,' * 39} n40) = n40
-
- foo(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
- }
- end
-
- def test_putself
- assert_compiles '3', %q{
- class Integer
- def minus(a)
- self - a
- end
- end
- 5.minus(2)
- }
- end
-
- def test_getinstancevariable
- assert_compiles 'nil', %q{
- def test() = @foo
-
- test()
- }
- assert_compiles '3', %q{
- @foo = 3
- def test() = @foo
-
- test()
- }
- end
-
- def test_getinstancevariable_miss
- assert_compiles '[1, 1, 4]', %q{
- class C
- def foo
- @foo
- end
-
- def foo_then_bar
- @foo = 1
- @bar = 2
- end
-
- def bar_then_foo
- @bar = 3
- @foo = 4
- end
- end
-
- o1 = C.new
- o1.foo_then_bar
- result = []
- result << o1.foo
- result << o1.foo
- o2 = C.new
- o2.bar_then_foo
- result << o2.foo
- result
- }
- end
-
- def test_setinstancevariable
- assert_compiles '1', %q{
- def test() = @foo = 1
-
- test()
- @foo
- }
- end
-
- def test_getclassvariable
- assert_compiles '42', %q{
- class Foo
- def self.test = @@x
- end
-
- Foo.class_variable_set(:@@x, 42)
- Foo.test()
- }
- end
-
- def test_getclassvariable_raises
- assert_compiles '"uninitialized class variable @@x in Foo"', %q{
- class Foo
- def self.test = @@x
- end
-
- begin
- Foo.test
- rescue NameError => e
- e.message
- end
- }
- end
-
- def test_setclassvariable
- assert_compiles '42', %q{
- class Foo
- def self.test = @@x = 42
- end
-
- Foo.test()
- Foo.class_variable_get(:@@x)
- }
- end
-
- def test_setclassvariable_raises
- assert_compiles '"can\'t modify frozen Class: Foo"', %q{
- class Foo
- def self.test = @@x = 42
- freeze
- end
-
- begin
- Foo.test
- rescue FrozenError => e
- e.message
- end
- }
- end
-
- def test_attr_reader
- assert_compiles '[4, 4]', %q{
- class C
- attr_reader :foo
-
- def initialize
- @foo = 4
- end
- end
-
- def test(c) = c.foo
- c = C.new
- [test(c), test(c)]
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_attr_accessor_getivar
- assert_compiles '[4, 4]', %q{
- class C
- attr_accessor :foo
-
- def initialize
- @foo = 4
- end
- end
-
- def test(c) = c.foo
- c = C.new
- [test(c), test(c)]
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_attr_accessor_setivar
- assert_compiles '[5, 5]', %q{
- class C
- attr_accessor :foo
-
- def initialize
- @foo = 4
- end
- end
-
- def test(c)
- c.foo = 5
- c.foo
- end
-
- c = C.new
- [test(c), test(c)]
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_attr_writer
- assert_compiles '[5, 5]', %q{
- class C
- attr_writer :foo
-
- def initialize
- @foo = 4
- end
-
- def get_foo = @foo
- end
-
- def test(c)
- c.foo = 5
- c.get_foo
- end
- c = C.new
- [test(c), test(c)]
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
def test_uncached_getconstant_path
assert_compiles RUBY_COPYRIGHT.dump, %q{
def test = RUBY_COPYRIGHT
@@ -3380,51 +171,6 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 1, insns: [:opt_getconstant_path]
end
- def test_getconstant
- assert_compiles '1', %q{
- class Foo
- CONST = 1
- end
-
- def test(klass)
- klass::CONST
- end
-
- test(Foo)
- test(Foo)
- }, call_threshold: 2, insns: [:getconstant]
- end
-
- def test_expandarray_no_splat
- assert_compiles '[3, 4]', %q{
- def test(o)
- a, b = o
- [a, b]
- end
- test [3, 4]
- }, call_threshold: 1, insns: [:expandarray]
- end
-
- def test_expandarray_splat
- assert_compiles '[3, [4]]', %q{
- def test(o)
- a, *b = o
- [a, b]
- end
- test [3, 4]
- }, call_threshold: 1, insns: [:expandarray]
- end
-
- def test_expandarray_splat_post
- assert_compiles '[3, [4], 5]', %q{
- def test(o)
- a, *b, c = o
- [a, b, c]
- end
- test [3, 4, 5]
- }, call_threshold: 1, insns: [:expandarray]
- end
-
def test_getconstant_path_autoload
# A constant-referencing expression can run arbitrary code through Kernel#autoload.
Dir.mktmpdir('autoload') do |tmpdir|
@@ -3439,78 +185,6 @@ class TestZJIT < Test::Unit::TestCase
end
end
- def test_constant_invalidation
- assert_compiles '123', <<~RUBY, call_threshold: 2, insns: [:opt_getconstant_path]
- class C; end
- def test = C
- test
- test
-
- C = 123
- test
- RUBY
- end
-
- def test_constant_path_invalidation
- assert_compiles '["Foo::C", "Foo::C", "Bar::C"]', <<~RUBY, call_threshold: 2, insns: [:opt_getconstant_path]
- module A
- module B; end
- end
-
- module Foo
- C = "Foo::C"
- end
-
- module Bar
- C = "Bar::C"
- end
-
- A::B = Foo
-
- def test = A::B::C
-
- result = []
-
- result << test
- result << test
-
- A::B = Bar
-
- result << test
- result
- RUBY
- end
-
- def test_single_ractor_mode_invalidation
- # Without invalidating the single-ractor mode, the test would crash
- assert_compiles '"errored but not crashed"', <<~RUBY, call_threshold: 2, insns: [:opt_getconstant_path]
- C = Object.new
-
- def test
- C
- rescue Ractor::IsolationError
- "errored but not crashed"
- end
-
- test
- test
-
- Ractor.new {
- test
- }.value
- RUBY
- end
-
- def test_dupn
- assert_compiles '[[1], [1, 1], :rhs, [nil, :rhs]]', <<~RUBY, insns: [:dupn]
- def test(array) = (array[1, 2] ||= :rhs)
-
- one = [1, 1]
- start_empty = []
- [test(one), one, test(start_empty), start_empty]
- RUBY
- end
-
def test_send_backtrace
backtrace = [
"-e:2:in 'Object#jit_frame1'",
@@ -3527,276 +201,6 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 2
end
- def test_bop_invalidation
- assert_compiles '100', %q{
- def test
- eval(<<~RUBY)
- class Integer
- def +(_) = 100
- end
- RUBY
- 1 + 2
- end
- test
- }
- end
-
- def test_defined_with_defined_values
- assert_compiles '["constant", "method", "global-variable"]', %q{
- class Foo; end
- def bar; end
- $ruby = 1
-
- def test = return defined?(Foo), defined?(bar), defined?($ruby)
-
- test
- }, insns: [:defined]
- end
-
- def test_defined_with_undefined_values
- assert_compiles '[nil, nil, nil]', %q{
- def test = return defined?(Foo), defined?(bar), defined?($ruby)
-
- test
- }, insns: [:defined]
- end
-
- def test_defined_with_method_call
- assert_compiles '["method", nil]', %q{
- def test = return defined?("x".reverse(1)), defined?("x".reverse(1).reverse)
-
- test
- }, insns: [:defined]
- end
-
- def test_defined_method_raise
- assert_compiles '[nil, nil, nil]', %q{
- class C
- def assert_equal expected, actual
- if expected != actual
- raise "NO"
- end
- end
-
- def test_defined_method
- assert_equal(nil, defined?("x".reverse(1).reverse))
- end
- end
-
- c = C.new
- result = []
- result << c.test_defined_method
- result << c.test_defined_method
- result << c.test_defined_method
- result
- }
- end
-
- def test_defined_yield
- assert_compiles "nil", "defined?(yield)"
- assert_compiles '[nil, nil, "yield"]', %q{
- def test = defined?(yield)
- [test, test, test{}]
- }, call_threshold: 2, insns: [:defined]
- end
-
- def test_defined_yield_from_block
- # This will do some EP hopping to find the local EP,
- # so it's slightly different than doing it outside of a block.
-
- assert_compiles '[nil, nil, "yield"]', %q{
- def test
- yield_self { yield_self { defined?(yield) } }
- end
-
- [test, test, test{}]
- }, call_threshold: 2
- end
-
- def test_block_given_p
- assert_compiles "false", "block_given?"
- assert_compiles '[false, false, true]', %q{
- def test = block_given?
- [test, test, test{}]
- }, call_threshold: 2, insns: [:opt_send_without_block]
- end
-
- def test_block_given_p_from_block
- # This will do some EP hopping to find the local EP,
- # so it's slightly different than doing it outside of a block.
-
- assert_compiles '[false, false, true]', %q{
- def test
- yield_self { yield_self { block_given? } }
- end
-
- [test, test, test{}]
- }, call_threshold: 2
- end
-
- def test_invokeblock_without_block_after_jit_call
- assert_compiles '"no block given (yield)"', %q{
- def test(*arr, &b)
- arr.class
- yield
- end
- begin
- test
- rescue => e
- e.message
- end
- }
- end
-
- def test_putspecialobject_vm_core_and_cbase
- assert_compiles '10', %q{
- def test
- alias bar test
- 10
- end
-
- test
- bar
- }, insns: [:putspecialobject]
- end
-
- def test_putspecialobject_const_base
- assert_compiles '1', %q{
- Foo = 1
-
- def test = Foo
-
- # First call: populates the constant cache
- test
- # Second call: triggers ZJIT compilation with warm cache
- # RubyVM::ZJIT.assert_compiles will panic if this fails to compile
- test
- }, call_threshold: 2
- end
-
- def test_branchnil
- assert_compiles '[2, nil]', %q{
- def test(x)
- x&.succ
- end
- [test(1), test(nil)]
- }, call_threshold: 1, insns: [:branchnil]
- end
-
- def test_nil_nil
- assert_compiles 'true', %q{
- def test = nil.nil?
- test
- }, insns: [:opt_nil_p]
- end
-
- def test_non_nil_nil
- assert_compiles 'false', %q{
- def test = 1.nil?
- test
- }, insns: [:opt_nil_p]
- end
-
- def test_getspecial_last_match
- assert_compiles '"hello"', %q{
- def test(str)
- str =~ /hello/
- $&
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_match_pre
- assert_compiles '"hello "', %q{
- def test(str)
- str =~ /world/
- $`
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_match_post
- assert_compiles '" world"', %q{
- def test(str)
- str =~ /hello/
- $'
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_match_last_group
- assert_compiles '"world"', %q{
- def test(str)
- str =~ /(hello) (world)/
- $+
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_numbered_match_1
- assert_compiles '"hello"', %q{
- def test(str)
- str =~ /(hello) (world)/
- $1
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_numbered_match_2
- assert_compiles '"world"', %q{
- def test(str)
- str =~ /(hello) (world)/
- $2
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_numbered_match_nonexistent
- assert_compiles 'nil', %q{
- def test(str)
- str =~ /(hello)/
- $2
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_no_match
- assert_compiles 'nil', %q{
- def test(str)
- str =~ /xyz/
- $&
- end
- test("hello world")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_complex_pattern
- assert_compiles '"123"', %q{
- def test(str)
- str =~ /(\d+)/
- $1
- end
- test("abc123def")
- }, insns: [:getspecial]
- end
-
- def test_getspecial_multiple_groups
- assert_compiles '"456"', %q{
- def test(str)
- str =~ /(\d+)-(\d+)/
- $2
- end
- test("123-456")
- }, insns: [:getspecial]
- end
-
# tool/ruby_vm/views/*.erb relies on the zjit instructions a) being contiguous and
# b) being reliably ordered after all the other instructions.
def test_instruction_order
@@ -3880,653 +284,6 @@ class TestZJIT < Test::Unit::TestCase
}
end
- def test_profile_under_nested_jit_call
- assert_compiles '[nil, nil, 3]', %q{
- def profile
- 1 + 2
- end
-
- def jit_call(flag)
- if flag
- profile
- end
- end
-
- def entry(flag)
- jit_call(flag)
- end
-
- [entry(false), entry(false), entry(true)]
- }, call_threshold: 2
- end
-
- def test_bop_redefined
- assert_runs '[3, :+, 100]', %q{
- def test
- 1 + 2
- end
-
- test # profile opt_plus
- [test, Integer.class_eval { def +(_) = 100 }, test]
- }, call_threshold: 2
- end
-
- def test_bop_redefined_with_adjacent_patch_points
- assert_runs '[15, :+, 100]', %q{
- def test
- 1 + 2 + 3 + 4 + 5
- end
-
- test # profile opt_plus
- [test, Integer.class_eval { def +(_) = 100 }, test]
- }, call_threshold: 2
- end
-
- # ZJIT currently only generates a MethodRedefined patch point when the method
- # is called on the top-level self.
- def test_method_redefined_with_top_self
- assert_runs '["original", "redefined"]', %q{
- def foo
- "original"
- end
-
- def test = foo
-
- test; test
-
- result1 = test
-
- # Redefine the method
- def foo
- "redefined"
- end
-
- result2 = test
-
- [result1, result2]
- }, call_threshold: 2
- end
-
- def test_method_redefined_with_module
- assert_runs '["original", "redefined"]', %q{
- module Foo
- def self.foo = "original"
- end
-
- def test = Foo.foo
- test
- result1 = test
-
- def Foo.foo = "redefined"
- result2 = test
-
- [result1, result2]
- }, call_threshold: 2
- end
-
- def test_module_name_with_guard_passes
- assert_compiles '"Integer"', %q{
- def test(mod)
- mod.name
- end
-
- test(String)
- test(Integer)
- }, call_threshold: 2
- end
-
- def test_module_name_with_guard_side_exit
- # This test demonstrates that the guard side exit works correctly
- # In this case, when we call with a non-Class object, it should fall back to interpreter
- assert_compiles '["String", "Integer", "Bar"]', %q{
- class MyClass
- def name = "Bar"
- end
-
- def test(mod)
- mod.name
- end
-
- results = []
- results << test(String)
- results << test(Integer)
- results << test(MyClass.new)
-
- results
- }, call_threshold: 2
- end
-
- def test_objtostring_calls_to_s_on_non_strings
- assert_compiles '["foo", "foo"]', %q{
- results = []
-
- class Foo
- def to_s
- "foo"
- end
- end
-
- def test(str)
- "#{str}"
- end
-
- results << test(Foo.new)
- results << test(Foo.new)
-
- results
- }
- end
-
- def test_objtostring_rewrite_does_not_call_to_s_on_strings
- assert_compiles '["foo", "foo"]', %q{
- results = []
-
- class String
- def to_s
- "bad"
- end
- end
-
- def test(foo)
- "#{foo}"
- end
-
- results << test("foo")
- results << test("foo")
-
- results
- }
- end
-
- def test_objtostring_rewrite_does_not_call_to_s_on_string_subclasses
- assert_compiles '["foo", "foo"]', %q{
- results = []
-
- class StringSubclass < String
- def to_s
- "bad"
- end
- end
-
- foo = StringSubclass.new("foo")
-
- def test(str)
- "#{str}"
- end
-
- results << test(foo)
- results << test(foo)
-
- results
- }
- end
-
- def test_objtostring_profiled_string_fastpath
- assert_compiles '"foo"', %q{
- def test(str)
- "#{str}"
- end
- test('foo'); test('foo') # profile as string
- }, call_threshold: 2
- end
-
- def test_objtostring_profiled_string_subclass_fastpath
- assert_compiles '"foo"', %q{
- class MyString < String; end
-
- def test(str)
- "#{str}"
- end
-
- foo = MyString.new("foo")
- test(foo); test(foo) # still profiles as string
- }, call_threshold: 2
- end
-
- def test_objtostring_profiled_string_fastpath_exits_on_nonstring
- assert_compiles '"1"', %q{
- def test(str)
- "#{str}"
- end
-
- test('foo') # profile as string
- test(1)
- }, call_threshold: 2
- end
-
- def test_objtostring_profiled_nonstring_calls_to_s
- assert_compiles '"[1, 2, 3]"', %q{
- def test(str)
- "#{str}"
- end
-
- test([1,2,3]); # profile as nonstring
- test([1,2,3]);
- }, call_threshold: 2
- end
-
- def test_objtostring_profiled_nonstring_guard_exits_when_string
- assert_compiles '"foo"', %q{
- def test(str)
- "#{str}"
- end
-
- test([1,2,3]); # profiles as nonstring
- test('foo');
- }, call_threshold: 2
- end
-
- def test_string_bytesize_with_guard
- assert_compiles '5', %q{
- def test(str)
- str.bytesize
- end
-
- test('hello')
- test('world')
- }, call_threshold: 2
- end
-
- def test_string_bytesize_multibyte
- assert_compiles '4', %q{
- def test(s)
- s.bytesize
- end
-
- test("💎")
- }, call_threshold: 2
- end
-
- def test_nil_value_nil_opt_with_guard
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(nil)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_nil_value_nil_opt_with_guard_side_exit
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(nil)
- test(nil)
- test(1)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_true_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(true)
- test(true)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_true_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(true)
- test(true)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_false_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(false)
- test(false)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_false_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(false)
- test(false)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_integer_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(1)
- test(2)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_integer_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(1)
- test(2)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_float_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(1.0)
- test(2.0)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_float_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(1.0)
- test(2.0)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_symbol_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(:foo)
- test(:bar)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_symbol_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(:foo)
- test(:bar)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_class_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(String)
- test(Integer)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_class_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(String)
- test(Integer)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_module_nil_opt_with_guard
- assert_compiles 'false', %q{
- def test(val) = val.nil?
-
- test(Enumerable)
- test(Kernel)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_module_nil_opt_with_guard_side_exit
- assert_compiles 'true', %q{
- def test(val) = val.nil?
-
- test(Enumerable)
- test(Kernel)
- test(nil)
- }, call_threshold: 2, insns: [:opt_nil_p]
- end
-
- def test_basic_object_guard_works_with_immediate
- assert_compiles 'NilClass', %q{
- class Foo; end
-
- def test(val) = val.class
-
- test(Foo.new)
- test(Foo.new)
- test(nil)
- }, call_threshold: 2
- end
-
- def test_basic_object_guard_works_with_false
- assert_compiles 'FalseClass', %q{
- class Foo; end
-
- def test(val) = val.class
-
- test(Foo.new)
- test(Foo.new)
- test(false)
- }, call_threshold: 2
- end
-
- def test_string_concat
- assert_compiles '"123"', %q{
- def test = "#{1}#{2}#{3}"
-
- test
- }, insns: [:concatstrings]
- end
-
- def test_string_concat_empty
- assert_compiles '""', %q{
- def test = "#{}"
-
- test
- }, insns: [:concatstrings]
- end
-
- def test_regexp_interpolation
- assert_compiles '/123/', %q{
- def test = /#{1}#{2}#{3}/
-
- test
- }, insns: [:toregexp]
- end
-
- def test_new_range_non_leaf
- assert_compiles '(0/1)..1', %q{
- def jit_entry(v) = make_range_then_exit(v)
-
- def make_range_then_exit(v)
- range = (v..1)
- super rescue range # TODO(alan): replace super with side-exit intrinsic
- end
-
- jit_entry(0) # profile
- jit_entry(0) # compile
- jit_entry(0/1r) # run without stub
- }, call_threshold: 2
- end
-
- def test_raise_in_second_argument
- assert_compiles '{ok: true}', %q{
- def write(hash, key)
- hash[key] = raise rescue true
- hash
- end
-
- write({}, :ok)
- }
- end
-
- def test_ivar_attr_reader_optimization_with_multi_ractor_mode
- assert_compiles '42', %q{
- class Foo
- class << self
- attr_accessor :bar
-
- def get_bar
- bar
- rescue Ractor::IsolationError
- 42
- end
- end
- end
-
- Foo.bar = [] # needs to be a ractor unshareable object
-
- def test
- Foo.get_bar
- end
-
- test
- test
-
- Ractor.new { test }.value
- }, call_threshold: 2
- end
-
- def test_ivar_get_with_multi_ractor_mode
- assert_compiles '42', %q{
- class Foo
- def self.set_bar
- @bar = [] # needs to be a ractor unshareable object
- end
-
- def self.bar
- @bar
- rescue Ractor::IsolationError
- 42
- end
- end
-
- Foo.set_bar
-
- def test
- Foo.bar
- end
-
- test
- test
-
- Ractor.new { test }.value
- }, call_threshold: 2
- end
-
- def test_ivar_get_with_already_multi_ractor_mode
- assert_compiles '42', %q{
- class Foo
- def self.set_bar
- @bar = [] # needs to be a ractor unshareable object
- end
-
- def self.bar
- @bar
- rescue Ractor::IsolationError
- 42
- end
- end
-
- Foo.set_bar
- r = Ractor.new {
- Ractor.receive
- Foo.bar
- }
-
- Foo.bar
- Foo.bar
-
- r << :go
- r.value
- }, call_threshold: 2
- end
-
- def test_ivar_set_with_multi_ractor_mode
- assert_compiles '42', %q{
- class Foo
- def self.bar
- _foo = 1
- _bar = 2
- begin
- @bar = _foo + _bar
- rescue Ractor::IsolationError
- 42
- end
- end
- end
-
- def test
- Foo.bar
- end
-
- test
- test
-
- Ractor.new { test }.value
- }
- end
-
- def test_struct_set
- assert_compiles '[42, 42, :frozen_error]', %q{
- C = Struct.new(:foo).new(1)
-
- def test
- C.foo = Object.new
- 42
- end
-
- r = [test, test]
- C.freeze
- r << begin
- test
- rescue FrozenError
- :frozen_error
- end
- }, call_threshold: 2
- end
-
- def test_global_tracepoint
- assert_compiles 'true', %q{
- def foo = 1
-
- foo
- foo
-
- called = false
-
- tp = TracePoint.new(:return) { |event|
- if event.method_id == :foo
- called = true
- end
- }
- tp.enable do
- foo
- end
- called
- }
- end
-
- def test_local_tracepoint
- assert_compiles 'true', %q{
- def foo = 1
-
- foo
- foo
-
- called = false
-
- tp = TracePoint.new(:return) { |_| called = true }
- tp.enable(target: method(:foo)) do
- foo
- end
- called
- }
- end
-
def test_line_tracepoint_on_c_method
assert_compiles '"[[:line, true]]"', %q{
events = []
@@ -4573,203 +330,6 @@ class TestZJIT < Test::Unit::TestCase
}
end
- def test_opt_case_dispatch
- assert_compiles '[true, false]', %q{
- def test(x)
- case x
- when :foo
- true
- else
- false
- end
- end
-
- results = []
- results << test(:foo)
- results << test(1)
- results
- }, insns: [:opt_case_dispatch]
- end
-
- def test_stack_overflow
- assert_compiles 'nil', %q{
- def recurse(n)
- return if n == 0
- recurse(n-1)
- nil # no tail call
- end
-
- recurse(2)
- recurse(2)
- begin
- recurse(20_000)
- rescue SystemStackError
- # Not asserting an exception is raised here since main
- # thread stack size is environment-sensitive. Only
- # that we don't crash or infinite loop.
- end
- }, call_threshold: 2
- end
-
- def test_invokeblock
- assert_compiles '42', %q{
- def test
- yield
- end
- test { 42 }
- }, insns: [:invokeblock]
- end
-
- def test_invokeblock_with_args
- assert_compiles '3', %q{
- def test(x, y)
- yield x, y
- end
- test(1, 2) { |a, b| a + b }
- }, insns: [:invokeblock]
- end
-
- def test_invokeblock_no_block_given
- assert_compiles ':error', %q{
- def test
- yield rescue :error
- end
- test
- }, insns: [:invokeblock]
- end
-
- def test_invokeblock_multiple_yields
- assert_compiles "[1, 2, 3]", %q{
- results = []
- def test
- yield 1
- yield 2
- yield 3
- end
- test { |x| results << x }
- results
- }, insns: [:invokeblock]
- end
-
- def test_ccall_variadic_with_multiple_args
- assert_compiles "[1, 2, 3]", %q{
- def test
- a = []
- a.push(1, 2, 3)
- a
- end
-
- test
- test
- }, insns: [:opt_send_without_block]
- end
-
- def test_ccall_variadic_with_no_args
- assert_compiles "[1]", %q{
- def test
- a = [1]
- a.push
- end
-
- test
- test
- }, insns: [:opt_send_without_block]
- end
-
- def test_ccall_variadic_with_no_args_causing_argument_error
- assert_compiles ":error", %q{
- def test
- format
- rescue ArgumentError
- :error
- end
-
- test
- test
- }, insns: [:opt_send_without_block]
- end
-
- def test_allocating_in_hir_c_method_is
- assert_compiles ":k", %q{
- # Put opt_new in a frame JIT code sets up that doesn't set cfp->pc
- def a(f) = test(f)
- def test(f) = (f.new if f)
- # A parallel couple methods that will set PC at the same stack height
- def second = third
- def third = nil
-
- a(nil)
- a(nil)
-
- class Foo
- def self.new = :k
- end
-
- second
-
- a(Foo)
- }, call_threshold: 2, insns: [:opt_new]
- end
-
- def test_singleton_class_invalidation_annotated_ccall
- assert_compiles '[false, true]', %q{
- def define_singleton(obj, define)
- if define
- # Wrap in C method frame to avoid exiting JIT on defineclass
- [nil].reverse_each do
- class << obj
- def ==(_)
- true
- end
- end
- end
- end
- false
- end
-
- def test(define)
- obj = BasicObject.new
- # This == call gets compiled to a CCall
- obj == define_singleton(obj, define)
- end
-
- result = []
- result << test(false) # Compiles BasicObject#==
- result << test(true) # Should use singleton#== now
- result
- }, call_threshold: 2
- end
-
- def test_singleton_class_invalidation_optimized_variadic_ccall
- assert_compiles '[1, 1000]', %q{
- def define_singleton(arr, define)
- if define
- # Wrap in C method frame to avoid exiting JIT on defineclass
- [nil].reverse_each do
- class << arr
- def push(x)
- super(x * 1000)
- end
- end
- end
- end
- 1
- end
-
- def test(define)
- arr = []
- val = define_singleton(arr, define)
- arr.push(val) # This CCall should be invalidated if singleton was defined
- arr[0]
- end
-
- result = []
- result << test(false) # Compiles Array#push as CCall
- result << test(true) # Singleton defined, CCall should be invalidated
- result
- }, call_threshold: 2
- end
-
def test_regression_cfp_sp_set_correctly_before_leaf_gc_call
assert_compiles ':ok', %q{
def check(l, r)
@@ -4799,60 +359,6 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 14, num_profiles: 5
end
- def test_is_a_string_special_case
- assert_compiles '[true, false, false, false, false, false]', %q{
- def test(x)
- x.is_a?(String)
- end
- test("foo")
- [test("bar"), test(1), test(false), test(:foo), test([]), test({})]
- }
- end
-
- def test_is_a_array_special_case
- assert_compiles '[true, true, false, false, false, false, false]', %q{
- def test(x)
- x.is_a?(Array)
- end
- test([])
- [test([1,2,3]), test([]), test(1), test(false), test(:foo), test("foo"), test({})]
- }
- end
-
- def test_is_a_hash_special_case
- assert_compiles '[true, true, false, false, false, false, false]', %q{
- def test(x)
- x.is_a?(Hash)
- end
- test({})
- [test({:a => "b"}), test({}), test(1), test(false), test(:foo), test([]), test("foo")]
- }
- end
-
- def test_is_a_hash_subclass
- assert_compiles 'true', %q{
- class MyHash < Hash
- end
- def test(x)
- x.is_a?(Hash)
- end
- test({})
- test(MyHash.new)
- }
- end
-
- def test_is_a_normal_case
- assert_compiles '[true, false]', %q{
- class MyClass
- end
- def test(x)
- x.is_a?(MyClass)
- end
- test("a")
- [test(MyClass.new), test("a")]
- }
- end
-
def test_exit_tracing
# This is a very basic smoke test. The StackProf format
# this option generates is external to us.