diff options
| -rw-r--r-- | zjit/bindgen/src/main.rs | 2 | ||||
| -rw-r--r-- | zjit/src/cruby.rs | 15 | ||||
| -rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 2 |
3 files changed, 18 insertions, 1 deletions
diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index 975a2d9157..77d482db4e 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -130,6 +130,8 @@ fn main() { .allowlist_function("rb_singleton_class") .allowlist_function("rb_define_class") .allowlist_function("rb_class_get_superclass") + .allowlist_function("rb_gc_disable_no_rest") + .allowlist_function("rb_gc_enable") .allowlist_function("rb_gc_mark") .allowlist_function("rb_gc_mark_movable") .allowlist_function("rb_gc_location") diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index 1a2dce03ed..4eb1d3a17c 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -890,6 +890,14 @@ where let mut recursive_lock_level: c_uint = 0; unsafe { rb_jit_vm_lock_then_barrier(&mut recursive_lock_level, file, line) }; + // Ensure GC is off while we have the VM lock because: + // 1. We create many transient Rust collections that hold VALUEs during compilation. + // It's extremely tricky to properly marked and reference update these, not to + // mention the overhead and ergonomics issues. + // 2. If we yield to the GC while compiling, it re-enters our mark and update functions. + // This breaks `&mut` exclusivity since mark functions derive fresh `&mut` from statics + // while there is a stack frame below it that has an overlapping `&mut`. That's UB. + let gc_disabled_pre_call = unsafe { rb_gc_disable_no_rest() }.test(); let ret = match catch_unwind(func) { Ok(result) => result, @@ -909,7 +917,12 @@ where } }; - unsafe { rb_jit_vm_unlock(&mut recursive_lock_level, file, line) }; + unsafe { + if !gc_disabled_pre_call { + rb_gc_enable(); + } + rb_jit_vm_unlock(&mut recursive_lock_level, file, line); + }; ret } diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index f18c0035ee..6a6263ab15 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -745,6 +745,7 @@ unsafe extern "C" { pub fn rb_gc_mark(obj: VALUE); pub fn rb_gc_mark_movable(obj: VALUE); pub fn rb_gc_location(obj: VALUE) -> VALUE; + pub fn rb_gc_enable() -> VALUE; pub fn rb_gc_writebarrier(old: VALUE, young: VALUE); pub fn rb_class_get_superclass(klass: VALUE) -> VALUE; pub static mut rb_cObject: VALUE; @@ -876,6 +877,7 @@ unsafe extern "C" { buff_size: usize, obj: VALUE, ) -> *const ::std::os::raw::c_char; + pub fn rb_gc_disable_no_rest() -> VALUE; pub fn rb_ec_stack_check(ec: *mut rb_execution_context_struct) -> ::std::os::raw::c_int; pub fn rb_gc_writebarrier_remember(obj: VALUE); pub fn rb_shape_id_offset() -> i32; |
