|
1 | 1 | use std::cell::Cell;
|
2 | 2 | use std::rc::Rc;
|
| 3 | +use std::ffi::{c_int}; |
3 | 4 |
|
4 | 5 | use crate::asm::Label;
|
5 | 6 | use crate::backend::current::{Reg, ALLOC_REGS};
|
@@ -446,8 +447,18 @@ fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -
|
446 | 447 | /// can't optimize the level=0 case using the SP register.
|
447 | 448 | fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, local_ep_offset: u32, level: u32) -> Option<()> {
|
448 | 449 | let ep = gen_get_ep(asm, level);
|
449 |
| - let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?); |
450 |
| - asm.mov(Opnd::mem(64, ep, offset), val); |
| 450 | + let local_index = c_int::try_from(local_ep_offset).ok().and_then(|idx| idx.checked_mul(-1))?; |
| 451 | + match val { |
| 452 | + // If we're writing a constant, non-heap VALUE, do a raw memory write without |
| 453 | + // running write barrier. |
| 454 | + lir::Opnd::Value(const_val) if const_val.special_const_p() => { |
| 455 | + let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).ok()?); |
| 456 | + asm.mov(Opnd::mem(64, ep, offset), val); |
| 457 | + } |
| 458 | + // We're potentially writing a reference to an IMEMO/env object, |
| 459 | + // so take care of the write barrier with a function. |
| 460 | + _ => { asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), val); } |
| 461 | + } |
451 | 462 | Some(())
|
452 | 463 | }
|
453 | 464 |
|
|
0 commit comments