ZJIT: Fix ObjToString rewrite (#14196)

ZJIT: Fix ObjToString rewrite

Currently, the rewrite for `ObjToString` always replaces it with a
`SendWithoutBlock(to_s)` instruction when the receiver is not a
string literal. This is incorrect because it calls `to_s` on the
receiver even if it's already a string.

This change fixes it by:
- Avoiding the `SendWithoutBlock(to_s)` rewrite
- Implement codegen for `ObjToString`
This commit is contained in:
Stan Lo 2025-08-13 21:03:26 +01:00 committed by GitHub
parent ff622978d0
commit 2b16f27a35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 6 deletions

View file

@ -1343,6 +1343,71 @@ class TestZJIT < Test::Unit::TestCase
}, 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_string_bytesize_with_guard
assert_compiles '5', %q{
def test(str)