Allow encodings to be autoloaded through transcoding functions

Make sure VM lock is not held when calling `load_transcoder_entry`, as
that causes deadlock inside ractors. `String#encode` now works inside
ractors, among others.

Atomic load the rb_encoding_list

Without this, wbcheck would sometimes hit a missing write barrier.

Co-authored-by: John Hawthorn <john.hawthorn@shopify.com>

Hold VM lock when iterating over global_enc_table.names

This st_table can be inserted into at runtime when autoloading
encodings.

minor optimization when calling Encoding.list
This commit is contained in:
Luke Gruber 2025-08-06 14:30:03 -04:00 committed by John Hawthorn
parent 31e8a9fced
commit 1afc07e815
4 changed files with 157 additions and 94 deletions

View file

@ -2320,6 +2320,46 @@ class TestTranscode < Test::Unit::TestCase
assert_equal("A\nB\nC", s.encode(usascii, newline: :lf))
end
def test_ractor_lazy_load_encoding
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
rs = []
autoload_encodings = Encoding.list.select { |e| e.inspect.include?("(autoload)") }.freeze
7.times do
rs << Ractor.new(autoload_encodings) do |encodings|
str = "\u0300"
encodings.each do |enc|
str.encode(enc) rescue Encoding::UndefinedConversionError
end
end
end
while rs.any?
r, _obj = Ractor.select(*rs)
rs.delete(r)
end
assert rs.empty?
end;
end
def test_ractor_lazy_load_encoding_random
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
rs = []
100.times do
rs << Ractor.new do
"\u0300".encode(Encoding.list.sample) rescue Encoding::UndefinedConversionError
end
end
while rs.any?
r, _obj = Ractor.select(*rs)
rs.delete(r)
end
assert rs.empty?
end;
end
private
def assert_conversion_both_ways_utf8(utf8, raw, encoding)