ZJIT: Add insns param that tests for opcode presence

This commit is contained in:
Alan Wu 2025-06-05 23:45:42 +09:00 committed by GitHub
parent 998e5791c5
commit 01f6bd8bc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-06-05 14:45:57 +00:00
Merged: https://github.com/ruby/ruby/pull/13470

Merged-By: XrXr

View File

@ -152,7 +152,7 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a == b
test(0, 2) # profile opt_eq
[test(1, 1), test(0, 1)]
}, call_threshold: 2
}, insns: [:opt_eq], call_threshold: 2
end
def test_opt_neq_dynamic
@ -162,7 +162,7 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a != b
test(0, 2) # profile opt_neq
[test(1, 1), test(0, 1)]
}, call_threshold: 1
}, insns: [:opt_neq], call_threshold: 1
end
def test_opt_neq_fixnum
@ -178,7 +178,7 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a < b
test(2, 3) # profile opt_lt
[test(0, 1), test(0, 0), test(1, 0)]
}, call_threshold: 2
}, insns: [:opt_lt], call_threshold: 2
end
def test_opt_lt_with_literal_lhs
@ -186,7 +186,7 @@ class TestZJIT < Test::Unit::TestCase
def test(n) = 2 < n
test(2) # profile opt_lt
[test(1), test(2), test(3)]
}, call_threshold: 2
}, insns: [:opt_lt], call_threshold: 2
end
def test_opt_le
@ -194,7 +194,7 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a <= b
test(2, 3) # profile opt_le
[test(0, 1), test(0, 0), test(1, 0)]
}, call_threshold: 2
}, insns: [:opt_le], call_threshold: 2
end
def test_opt_gt
@ -202,7 +202,7 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a > b
test(2, 3) # profile opt_gt
[test(0, 1), test(0, 0), test(1, 0)]
}, call_threshold: 2
}, insns: [:opt_gt], call_threshold: 2
end
def test_opt_ge
@ -210,14 +210,14 @@ class TestZJIT < Test::Unit::TestCase
def test(a, b) = a >= b
test(2, 3) # profile opt_ge
[test(0, 1), test(0, 0), test(1, 0)]
}, call_threshold: 2
}, insns: [:opt_ge], call_threshold: 2
end
def test_new_array_empty
assert_compiles '[]', %q{
def test = []
test
}
}, insns: [:newarray]
end
def test_new_array_nonempty
@ -551,7 +551,7 @@ class TestZJIT < Test::Unit::TestCase
# Assert that every method call in `test_script` can be compiled by ZJIT
# at a given call_threshold
def assert_compiles(expected, test_script, **opts)
def assert_compiles(expected, test_script, insns: [], **opts)
pipe_fd = 3
script = <<~RUBY
@ -559,18 +559,39 @@ class TestZJIT < Test::Unit::TestCase
RubyVM::ZJIT.assert_compiles
#{test_script}
}
result = _test_proc.call
IO.open(#{pipe_fd}).write(result.inspect)
ret_val = _test_proc.call
result = {
ret_val:,
#{ unless insns.empty?
'insns: RubyVM::InstructionSequence.of(_test_proc).enum_for(:each_child).map(&:to_a)'
end}
}
IO.open(#{pipe_fd}).write(Marshal.dump(result))
RUBY
status, out, err, actual = eval_with_jit(script, pipe_fd:, **opts)
status, out, err, result = eval_with_jit(script, pipe_fd:, **opts)
message = "exited with status #{status.to_i}"
message << "\nstdout:\n```\n#{out}```\n" unless out.empty?
message << "\nstderr:\n```\n#{err}```\n" unless err.empty?
assert status.success?, message
assert_equal expected, actual
result = Marshal.load(result)
assert_equal expected, result.fetch(:ret_val).inspect
unless insns.empty?
iseqs = result.fetch(:insns)
iseqs.filter! { it[9] == :method } # ISeq type
assert_equal 1, iseqs.size, "Opcode assertions tests must define exactly one method"
iseq_insns = iseqs.first.last
expected_insns = Set.new(insns)
iseq_insns.each do
next unless it.is_a?(Array)
expected_insns.delete(it.first)
end
assert(expected_insns.empty?, -> { "Not present in ISeq: #{expected_insns.to_a}" })
end
end
# Run a Ruby process with ZJIT options and a pipe for writing test results