Bug #22421
open`RubyVM::YJIT.max_compile_time_ns=` aborts the process when YJIT is not enabled
Description
Calling RubyVM::YJIT.max_compile_time_ns= (added by [Feature #22236]) before YJIT is enabled aborts the process with a Rust panic.
$ ruby -v
ruby 4.1.0dev (2026-10-09T00:54:42Z master 21f68cfec7) +PRISM [x86_64-linux]
$ ruby -e 'RubyVM::YJIT.max_compile_time_ns = 10'
thread '<unnamed>' (10) panicked at /usr/src/ruby/yjit/src/codegen.rs:11313:43:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread '<unnamed>' (10) panicked at .../library/core/src/panicking.rs:225:5:
panic in a function that cannot unwind
Aborted (core dumped)
The same happens with ruby --yjit-disable -e 'RubyVM::YJIT.max_compile_time_ns = 10'.
It works as expected once YJIT is enabled, either with --yjit or after RubyVM::YJIT.enable:
$ ruby --yjit -e 'RubyVM::YJIT.max_compile_time_ns = 10; p RubyVM::YJIT.max_compile_time_ns'
10
$ ruby -e 'RubyVM::YJIT.enable; RubyVM::YJIT.max_compile_time_ns = 10; p RubyVM::YJIT.max_compile_time_ns'
10
The reader side does not crash (RubyVM::YJIT.max_compile_time_ns and RubyVM::YJIT.total_compile_time_ns return 0 when YJIT is not enabled).
The panic is the unwrap() in CodegenGlobals::get_instance() (yjit/src/codegen.rs), which is None until YJIT is initialized. Other YJIT methods that touch the globals (for example reset_stats! or enable) check CodegenGlobals::has_instance() or the enabled state first.
Expected behavior: either store the value so that it takes effect when YJIT is enabled later (useful for the warmup-budget use case in [Feature #22236], where the budget may be set early in a boot script), or raise a Ruby exception, but not abort the process.
Reproduced in the ghcr.io/ruby/ruby:master Docker image (x86_64-linux).
No data to display