summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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(())
}