summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zjit/bindgen/src/main.rs2
-rw-r--r--zjit/src/cruby.rs15
-rw-r--r--zjit/src/cruby_bindings.inc.rs2
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;