diff --git a/doc/string.rb b/doc/string.rb
index d68b40743b9d77..ad1abf29b7f55b 100644
--- a/doc/string.rb
+++ b/doc/string.rb
@@ -460,8 +460,7 @@
#
# _Substitution_
#
-# - #dump: Returns a copy of +self+ with all non-printing characters replaced by \xHH notation
-# and all special characters escaped.
+# - #dump: Returns a printable version of +self+, enclosed in double-quotes.
# - #undump: Returns a copy of +self+ with all \xNN notations replaced by \uNNNN notations
# and all escaped characters unescaped.
# - #sub: Returns a copy of +self+ with the first substring matching a given pattern
diff --git a/doc/string/each_byte.rdoc b/doc/string/each_byte.rdoc
index 643118fea3e47e..1f1069863b264b 100644
--- a/doc/string/each_byte.rdoc
+++ b/doc/string/each_byte.rdoc
@@ -1,17 +1,18 @@
-Calls the given block with each successive byte from +self+;
+With a block given, calls the block with each successive byte from +self+;
returns +self+:
- 'hello'.each_byte {|byte| print byte, ' ' }
- print "\n"
- 'тест'.each_byte {|byte| print byte, ' ' }
- print "\n"
- 'こんにちは'.each_byte {|byte| print byte, ' ' }
- print "\n"
+ a = []
+ 'hello'.each_byte {|byte| a.push(byte) } # Five 1-byte characters.
+ a # => [104, 101, 108, 108, 111]
+ a = []
+ 'тест'.each_byte {|byte| a.push(byte) } # Four 2-byte characters.
+ a # => [209, 130, 208, 181, 209, 129, 209, 130]
+ a = []
+ 'こんにちは'.each_byte {|byte| a.push(byte) } # Five 3-byte characters.
+ a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
-Output:
+With no block given, returns an enumerator.
+
+Related: see {Iterating}[rdoc-ref:String@Iterating].
- 104 101 108 108 111
- 209 130 208 181 209 129 209 130
- 227 129 147 227 130 147 227 129 171 227 129 161 227 129 175
-Returns an enumerator if no block is given.
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index 54346e077806c4..fee6537c375d49 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(())
}