diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 1b6838bb2e..0fa2c72d66 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -95,6 +95,7 @@ fn main() { // From ruby/internal/intern/object.h .allowlist_function("rb_obj_is_kind_of") + .allowlist_function("rb_obj_frozen_p") // From ruby/internal/encoding/encoding.h .allowlist_type("ruby_encoding_consts") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 6b2ef6806f..c60264078b 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -2191,6 +2191,12 @@ fn gen_setinstancevariable( let comptime_receiver = jit_peek_at_self(jit); let comptime_val_klass = comptime_receiver.class_of(); + // If the comptime receiver is frozen, writing an IV will raise an exception + // and we don't want to JIT code to deal with that situation. + if comptime_receiver.is_frozen() { + return CantCompile; + } + // Check if the comptime class uses a custom allocator let custom_allocator = unsafe { rb_get_alloc_func(comptime_val_klass) }; let uses_custom_allocator = match custom_allocator { diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs index c2f5790620..b6228fe64b 100644 --- a/yjit/src/cruby.rs +++ b/yjit/src/cruby.rs @@ -394,6 +394,10 @@ impl VALUE { unsafe { CLASS_OF(self) } } + pub fn is_frozen(self) -> bool { + unsafe { rb_obj_frozen_p(self) != VALUE(0) } + } + pub fn shape_id_of(self) -> u32 { unsafe { rb_shape_get_shape_id(self) } } diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index e797c19104..d2ad67e802 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -357,6 +357,9 @@ extern "C" { extern "C" { pub fn rb_obj_is_kind_of(obj: VALUE, klass: VALUE) -> VALUE; } +extern "C" { + pub fn rb_obj_frozen_p(obj: VALUE) -> VALUE; +} extern "C" { pub fn rb_backref_get() -> VALUE; }