我们很高兴地宣布 Ruby 3.3.0 正式发布。Ruby 3.3 添加了名为 Prism 的新解析器,使用 Lrama 作为解析器生成器,添加了名为 RJIT 的新纯 Ruby JIT 编译器,并特别对 YJIT 进行了许多性能改进。
棱镜
引入 Prism 解析器作为默认 gem
Prism 是 Ruby 语言的一个可移植、容错和可维护的递归下降解析器
Prism 已投入生产并得到积极维护,你可以用它来替代 Ripper
有大量文档介绍如何使用 Prism
Prism 既是 CRuby 内部使用的 C 语言库,也是 Ruby gem,任何需要解析 Ruby 代码的工具都可以使用它。
Prism API 中值得注意的方法有
Prism.parse(source) 作为解析结果对象的一部分返回 AST
Prism.parse_comments(source) 返回注释
Prism.parse_success?(source) 如果没有错误,则返回 “true”。
如果您有兴趣贡献自己的力量,可以直接在 Prism 代码库中提出拉取请求或问题
您现在可以使用 ruby –parser=prism 或 RUBYOPT=”–parser=prism” 来尝试使用 Prism 编译器。请注意,此标记仅用于调试。
使用 Lrama 代替 Bison
用 Lrama LALR 解析器生成器取代 Bison [功能 #19637]
如果您有兴趣,请参阅 Ruby 解析器的未来愿景
为便于维护,用 Racc 生成的 LR 解析器替换 Lrama 内部解析器
支持参数化规则(?、*、+),它将用于 Ruby parse.y
YJIT
与 Ruby 3.2 相比在性能上有重大改进
改进了对 splat 和 rest 参数的支持。
为虚拟机的堆栈操作分配了寄存器。
编译了更多带有可选参数的调用。还编译了异常处理程序。
不支持的调用类型和巨型调用站点不再退出解释器。
内联了 Rails #blank? 和专门的 #present? 等基本方法。
对 Integer#*、Integer#!=、String#!=、String#getbyte、Kernel#block_given?、Kernel#is_a?、Kernel#instance_of? 和 Module#=== 进行了特别优化。
编译速度比 Ruby 3.2 稍快。
现在比 Optcarrot 上的解释器快 3 倍以上!
内存使用率比 Ruby 3.2 有显著提高
编译代码的元数据占用内存更少。
–当应用程序的 ISEQ 超过 40,000 个时,yjit-call-threshold 会自动从 30 提高到 120。
添加了–yjit-cold-threshold,以跳过编译冷 ISEQ。
在 Arm64 上生成的代码更紧凑。
代码 GC 现在默认为禁用
–yjit-exec-mem-size被视为停止编译新代码的硬限制。
代码 GC 不会导致性能突然下降。在使用 Pitchfork 进行重新分叉的服务器上,写入时复制行为更佳。
如果需要,仍可使用 –yjit-code-gc 启用代码 GC
添加 RubyVM::YJIT.enable,可在运行时启用 YJIT
你可以在不修改命令行参数或环境变量的情况下启动 YJIT。Rails 7.2 将使用此方法默认启用 YJIT。
也可以在应用程序启动完成后才启用 YJIT。如果想在启动时禁用 YJIT 的同时使用其他 YJIT 选项,可以使用 –yjit-disable 方法。
默认情况下可使用更多 YJIT 统计信息
yjit_alloc_size 和更多与元数据相关的统计信息现在默认可用。
由 –yjit-stats 生成的 ratio_in_yjit 统计信息现在可在发布版本中使用,不再需要特殊的 stats 或 dev 版本才能访问大多数统计信息。
添加更多剖析功能
添加了 –yjit-perf 以方便使用 Linux perf 进行剖析。
–yjit-trace-exits现在支持使用–yjit-trace-exits-sample-rate=N进行采样。
更全面的测试和多个错误修复
RJIT
引入纯 Ruby JIT 编译器 RJIT 并取代 MJIT。
RJIT 仅支持 Unix 平台上的 x86-64 架构。
与 MJIT 不同,它在运行时不需要 C 编译器。
RJIT 仅用于实验目的。
在生产中应继续使用 YJIT。
如果您对为 Ruby 开发 JIT 感兴趣,请查看 k0kubun 在 RubyKaigi 第 3 天的演讲。