Project

General

Profile

Actions

Bug #22551

open

YJIT: String#<< clears the receiver's coderange

Bug #22551: YJIT: String#<< clears the receiver's coderange

Added by rdil (Reece Dunham) about 19 hours ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:127491]

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

Also available in: PDF Atom