summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2025-07-22 15:49:36 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2025-07-22 18:04:28 -0400
commit33363030e1846c9f2cdbdcc9b77c11efbda3d522 (patch)
tree1724b16b0bcda244c80045ad77693ff0b17ad84f
parent465b1696adb0a9e6af8623ca6caaae69b71831be (diff)
ZJIT: Use rb_vm_env_write() for `hir::Insn::SetLocal`
We weren't firing write barriers before when writing to imemo/env objects. Wbcheck caught this with test/ruby/test_refinement.rb: ruby -v: ruby 3.5.0dev (2025-07-22T17:05:58Z wbcheck 2569a80954) +ZJIT dev +PRISM +GC[wbcheck] [x86_64-linux] WBCHECK ERROR: Missed write barrier detected! Parent object: 0x558de9f4e6e0 (wb_protected: true) rb_obj_info_dump: 0x0000558de9f4e6e0 T_IMEMO/<env> Reference counts - snapshot: 3, writebarrier: 0, current: 4, missed: 1 Missing reference to: 0x558decf37c30 rb_obj_info_dump: 0x0000558decf37c30 method/UnboundMethod method WBCHECK SUMMARY: Found 1 objects with missed write barriers (1 total violations)
-rw-r--r--zjit/src/codegen.rs17
1 files changed, 15 insertions, 2 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index 54346e0778..fee6537c37 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -1,5 +1,6 @@
use std::cell::Cell;
use std::rc::Rc;
+use std::ffi::{c_int};
use crate::asm::Label;
use crate::backend::current::{Reg, ALLOC_REGS};
@@ -446,8 +447,20 @@ fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -
/// can't optimize the level=0 case using the SP register.
fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, local_ep_offset: u32, level: u32) -> Option<()> {
let ep = gen_get_ep(asm, level);
- let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?);
- asm.mov(Opnd::mem(64, ep, offset), val);
+ match val {
+ // If we're writing a constant, non-heap VALUE, do a raw memory write without
+ // running write barrier.
+ lir::Opnd::Value(const_val) if const_val.special_const_p() => {
+ let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?);
+ asm.mov(Opnd::mem(64, ep, offset), val);
+ }
+ // We're potentially writing a reference to an IMEMO/env object,
+ // so take care of the write barrier with a function.
+ _ => {
+ let local_index = c_int::try_from(local_ep_offset).ok().and_then(|idx| idx.checked_mul(-1))?;
+ asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), val);
+ }
+ }
Some(())
}