Actions
Bug #22551
openYJIT: String#<< clears the receiver's coderange
Bug #22551:
YJIT: String#<< clears the receiver's coderange
Description
With YJIT, str << other leaves str with an unknown coderange when both strings have the same encoding. The interpreter keeps the coderange. Any later operation that needs it (length, [], valid_encoding?) then rescans the whole string, so code that appends and reads in a loop is much slower with YJIT than without.
# Run twice: `ruby repro.rb` and `ruby --yjit repro.rb`
require 'objspace'
require 'json'
def append(buf, chunk) = buf << chunk
def coderange(str) = JSON.parse(ObjectSpace.dump(str))['coderange'] || 'unknown'
chunk = 'é' * 100 # valid UTF-8, not ASCII
chunk.valid_encoding?
buf = +'é'
buf.valid_encoding?
1_000.times { append(+'é', chunk) } # let YJIT compile append
append(buf, chunk)
puts RUBY_DESCRIPTION
puts "coderange after <<: #{coderange(buf)}"
buf = +''
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
2_000.times do
append(buf, chunk)
buf.length
end
puts format('2,000 appends, each followed by #length: %.0f ms',
(Process.clock_gettime(Process::CLOCK_MONOTONIC) - started) * 1000)
Results on arm64 macOS:
| ruby | without YJIT | with --yjit |
|---|---|---|
| 3.3.13 | valid, 17 ms | unknown, 400 ms |
| 3.4.9 | valid, 17 ms | unknown, 477 ms |
| 4.0.5 | valid, 17 ms | unknown, 479 ms |
| 4.0.7 | valid, 17 ms | unknown, 504 ms |
No data to display
Actions