Skip to content

Commit 35b9f9d

Browse files
committed
ZJIT: Don't call write barrier if the object is an immediate
In addition to compile-time knowledge, we can also (now that the global regalloc has landed) check at run time if the value being stored is a heap object.
1 parent 896e5c4 commit 35b9f9d

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

zjit/src/codegen.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
668668
Insn::LoadSelf => gen_load_self(),
669669
&Insn::LoadField { recv, id, offset, return_type } => gen_load_field(asm, opnd!(recv), id, offset, return_type),
670670
&Insn::StoreField { recv, id, offset, val } => no_output!(gen_store_field(asm, opnd!(recv), id, offset, opnd!(val), function.type_of(val))),
671-
&Insn::WriteBarrier { recv, val } => no_output!(gen_write_barrier(asm, opnd!(recv), opnd!(val), function.type_of(val))),
671+
&Insn::WriteBarrier { recv, val } => no_output!(gen_write_barrier(jit, asm, opnd!(recv), opnd!(val), function.type_of(val))),
672672
&Insn::IsBlockGiven { lep } => gen_is_block_given(asm, opnd!(lep)),
673673
Insn::ArrayInclude { elements, target, state } => gen_array_include(jit, asm, opnds!(elements), opnd!(target), &function.frame_state(*state)),
674674
Insn::ArrayPackBuffer { elements, fmt, buffer, state } => gen_array_pack_buffer(jit, asm, opnds!(elements), opnd!(fmt), opnd!(buffer), &function.frame_state(*state)),
@@ -1286,13 +1286,35 @@ fn gen_store_field(asm: &mut Assembler, recv: Opnd, id: ID, offset: i32, val: Op
12861286
asm.store(Opnd::mem(val_type.num_bits(), recv, offset), val);
12871287
}
12881288

1289-
fn gen_write_barrier(asm: &mut Assembler, recv: Opnd, val: Opnd, val_type: Type) {
1289+
fn gen_write_barrier(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, val: Opnd, val_type: Type) {
12901290
// See RB_OBJ_WRITE/rb_obj_write: it's just assignment and rb_obj_written().
12911291
// rb_obj_written() does: if (!RB_SPECIAL_CONST_P(val)) { rb_gc_writebarrier(recv, val); }
12921292
if !val_type.is_immediate() {
12931293
asm_comment!(asm, "Write barrier");
12941294
let recv = asm.load(recv);
1295+
1296+
// Create a result block that all paths converge to
1297+
let hir_block_id = asm.current_block().hir_block_id;
1298+
let rpo_idx = asm.current_block().rpo_index;
1299+
let result_block = asm.new_block(hir_block_id, false, rpo_idx);
1300+
let result_edge = Target::Block(lir::BranchEdge { target: result_block, args: vec![] });
1301+
1302+
// If non-false immediate, don't fire write barrier
1303+
asm.test(val, Opnd::UImm(RUBY_IMMEDIATE_MASK as u64));
1304+
asm.jnz(jit, result_edge.clone());
1305+
1306+
// If false, don't fire write barrier
1307+
asm.cmp(val, Qfalse.into());
1308+
asm.je(jit, result_edge.clone());
1309+
1310+
// Heap object; fire the write barrier
12951311
asm_ccall!(asm, rb_zjit_writebarrier_check_immediate, recv, val);
1312+
asm.jmp(result_edge);
1313+
1314+
// Join block
1315+
asm.set_current_block(result_block);
1316+
let label = jit.get_label(asm, result_block, hir_block_id);
1317+
asm.write_label(label);
12961318
}
12971319
}
12981320

0 commit comments

Comments
 (0)