Skip to content

Instantly share code, notes, and snippets.

How TruffleRuby Implements svars ($~, $1, $2, etc.)

TruffleRuby's design centers on making the common case fast (no svars needed) while still supporting the frame-local, thread-local semantics Ruby requires. There are several layers of optimization.

1. Storage: SpecialVariableStorage at a Fixed Frame Slot

Every method frame reserves slot 1 for a SpecialVariableStorage object (see TranslatorEnvironment.java). Block frames do not get their own slot — they share the enclosing method's storage by walking up the declaration frame chain (the depth is cached per FrameDescriptor, so the JIT unrolls this).

SpecialVariableStorage itself is tiny — it holds just two fields:

  • lastMatch ($~) — a ThreadAndFrameLocalStorage
Parsing perf data files...
YJIT: perf-data/yjit-lobsters.data
ZJIT: perf-data/zjit-lobsters.data
==========================================================================================
PERF COMPARISON: YJIT vs ZJIT (Lobsters benchmark)
==========================================================================================
Metric YJIT ZJIT
----------------------------------------------------------------------
1727906473.260308: decode_from@/Users/nirvdrum/dev/workspaces/yjit-bench/benchmarks/protoboeuf-encode/benchmark_pb.rb:68
1727906473.261220: <cfunc> String#getbyte
1727906473.261770: <cfunc> String#getbyte
1727906473.262610: <cfunc> String#getbyte
1727906473.262978: <cfunc> String#getbyte
1727906473.263341: <cfunc> String#getbyte
1727906473.264131: <cfunc> String#getbyte
1727906473.264511: <cfunc> String#getbyte
1727906473.264867: <cfunc> String#getbyte
1727906473.265777: <cfunc> String#getbyte
if regexp.forced_utf8_encoding?
Encoding::UTF_8
elsif regexp.forced_binary_encoding?
Encoding::ASCII_8BIT
elsif regexp.forced_us_ascii_encoding?
Encoding::US_ASCII
elsif regexp.ascii_8bit?
Encoding::ASCII_8BIT
elsif regexp.utf_8?
Encoding::UTF_8
@nirvdrum
nirvdrum / cruby-3.3.0-yjit.txt
Last active February 15, 2024 16:22
Results of running the benchmarks for the Trilogy Ruby client
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +YJIT [x86_64-linux]
Warming up --------------------------------------
trilogy connect/close
1.112k i/100ms
mysql2 connect/close 955.000 i/100ms
Calculating -------------------------------------
trilogy connect/close
12.458k (± 7.5%) i/s - 62.272k in 5.032194s
mysql2 connect/close 9.952k (± 4.9%) i/s - 49.660k in 5.001969s

Regexp Encodings

There are two string values being updated as we go along:

  • RegularExpressionNode#unescaped
  • RegularExpressionNode#source

unescaped is supposed to be the source string according to the interface. However, it doesn't adapt to many situations.

| Regex | CRuby 3.3.0 Source | Prism RegularExpressioNode#unescaped (Pre-changes) |

> ruby -v
truffleruby 24.1.0-dev-677ac08b, like ruby 3.2.2, GraalVM CE Native [x86_64-linux]
Fatal error: No exception handler registered for deopt target
encodedBci: 113 (bci 24 rethrowException)
Method info: org.truffleruby.language.RubyProcRootNode.execute(RubyProcRootNode.java:77)
Partial Deoptimized Stack
org.truffleruby.language.RubyProcRootNode.execute(RubyProcRootNode.java:77)
@nirvdrum
nirvdrum / encoding_compatibility.java
Last active October 28, 2021 14:40
Ruby Encoding Compatibility Check
@Specialization(guards = {
"firstEncoding != secondEncoding",
"!isBroken(first, codeRangeNode)",
"!isBroken(second, codeRangeNode)"
})
protected RubyEncoding commonCases(
Rope first, RubyEncoding firstEncoding, Rope second, RubyEncoding secondEncoding) {
final CodeRange firstCodeRange = getCodeRange(first);
final CodeRange secondCodeRange = getCodeRange(second);
nirvdrum.com on  gh-pages [!?]
❯ rbenv shell jruby-9.2.12.0
nirvdrum.com on  gh-pages [!?]
❯ gem install jekyll
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/home/nirvdrum/.rbenv/versions/jruby-9.2.12.0/lib/ruby/stdlib/jopenssl.jar) to field java.security.MessageDigest.provider
WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
zsysd.loglevel=info msg="Building new machines list"
level=debug msg="ZFS: new scan"
level=debug msg="ZFS: refresh dataset list"
level=debug msg="New dataNew dataset found: \"rpool\""
level=debug msg="New dataNew dataset found: \"rpool/ROOT\""
level=debug msg="New dataNew dataset found: \"rpool/ROOT/ubuntu_bp7ow2\""
level=debug msg="property \"com.ubuntu.zsys:bootfs\" on dataset \"rpool/ROOT/ubuntu_bp7ow2\": value: \"yes\" source: \"local\""
level=debug msg="property \"com.ubuntu.zsys:last-used\" on dataset \"rpool/ROOT/ubuntu_bp7ow2\": value: \"1585700277\" source: \"local\""
level=debug msg="property \"com.ubuntu.zsys:last-booted-kernel\" on dataset \"rpool/ROOT/ubuntu_bp7ow2\": value: \"vmlinuz-5.4.0-18-generic\" source: \"local\""
level=debug msg="New dataNew dataset found: \"rpool/ROOT/ubuntu_bp7ow2/usr\""