Project

General

Profile

Actions

Bug #22546

open

YJIT panics in arm64 `add` when compiling a method with 495 or more locals

Bug #22546: YJIT panics in arm64 `add` when compiling a method with 495 or more locals

Added by jamescook83 (James Cook) about 2 hours ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.1.0dev (2026-11-13 master acc624e47b) +PRISM [arm64-darwin25]
[ruby-core:127472]

Description

Versions:

  • ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [arm64-darwin25]
  • ruby 4.1.0dev (2026-11-13 master acc624e47b) +PRISM [arm64-darwin25]
    macOS on Apple silicon.

Also reproduces on Linux:

  • ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [aarch64-linux] (ruby:4.0.9-slim Docker image, native arm64): same threshold, same panic at yjit/src/asm/arm64/mod.rs:53:78.
  • ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [x86_64-linux] (same image, x86_64 emulated with Rosetta on Apple silicon): a similar but different failure. 495 locals and up to 4089 compile and return correct values; at 4090 locals the process segfaults (exit 139) with no [BUG] output. Without --yjit it runs.
    Repro (run with ruby --yjit):
count = 600
body = (1..count).map { |n| "  v#{n} = a + #{n}" }.join("\n")
eval("def many_locals(a)\n#{body}\n  v1\nend")
100.times { many_locals(1) }

A local table of 494 entries compiles; 495 panics, the same on both versions. Stack depth does not move it (300 locals with a 220-element array literal compiles). Without --yjit every count runs. The attached yjit_repro.rb bisects the threshold, running each count in a child ruby --yjit.

Panic (4.1.0dev; 4.0.9 shows the same frames and the same line):

ruby: YJIT has panicked. More info to follow...
thread '<unnamed>' panicked at ./yjit/src/asm/arm64/mod.rs:53:78:
called `Result::unwrap()` on an `Err` value: ()
   3: yjit::asm::arm64::add
   4: <yjit::backend::ir::Assembler>::arm64_emit
   5: <yjit::backend::ir::Assembler>::compile_with_regs
   6: <yjit::backend::ir::Assembler>::compile
   7: yjit::codegen::gen_single_block
   8: yjit::core::gen_block_series
   9: yjit::core::branch_stub_hit_body
  12: yjit::core::branch_stub_hit
[BUG] YJIT: panicked at ./yjit/src/asm/arm64/mod.rs:53:78

Expected: no panic.

ZJIT on the same 4.1.0dev build compiles these methods (with --zjit-call-threshold=1) and runs them correctly up to 2048 locals; at 5000 it declines to compile and the interpreter runs it.

Use case. This came from a tool that compiles a small language to Ruby. Its output is long straight-line methods, and each intermediate result gets its own local, so one source function can produce a few hundred locals. Other generated code can reach similar counts: #22074 was found in production through a large Slim template with more than 256 locals. The method is valid Ruby and runs correctly in the interpreter, but under YJIT it aborts the whole process with [BUG]. Splitting the generated methods into smaller ones avoids it. The generator works around it now, but other generated code will hit the same limit.


Files

yjit_repro.rb (1.24 KB) yjit_repro.rb jamescook83 (James Cook), 11/13/2026 06:19 PM

No data to display

Actions

Also available in: PDF Atom