Skip to content

Commit cb33f22

Browse files
jhawthorntekknolagist0012
committed
ZJIT: Precise GC writebarriers
This issues writebarriers for objects added via gc_offsets or by profiling. This may be slower than writebarrier_remember, but we would like it to be more debuggable. Co-authored-by: Max Bernstein <[email protected]> Co-authored-by: Stan Lo <[email protected]>
1 parent 39b844e commit cb33f22

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

zjit/src/codegen.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::rc::Rc;
44
use crate::asm::Label;
55
use crate::backend::current::{Reg, ALLOC_REGS};
66
use crate::invariants::track_bop_assumption;
7-
use crate::gc::get_or_create_iseq_payload;
7+
use crate::gc::{get_or_create_iseq_payload, append_gc_offsets};
88
use crate::state::ZJITState;
99
use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr};
1010
use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, SideExitContext, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, SP};
@@ -124,7 +124,7 @@ fn gen_iseq_entry_point_body(cb: &mut CodeBlock, iseq: IseqPtr) -> *const u8 {
124124
// Remember the block address to reuse it later
125125
let payload = get_or_create_iseq_payload(iseq);
126126
payload.start_ptr = Some(start_ptr);
127-
payload.gc_offsets.extend(gc_offsets);
127+
append_gc_offsets(iseq, &gc_offsets);
128128

129129
// Compile an entry point to the JIT code
130130
(gen_entry(cb, iseq, &function, start_ptr, jit.c_stack_bytes), jit.branch_iseqs)
@@ -193,7 +193,7 @@ fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr) -> Option<(CodePtr, Vec<(Rc<Branc
193193
let result = gen_function(cb, iseq, &function);
194194
if let Some((start_ptr, gc_offsets, jit)) = result {
195195
payload.start_ptr = Some(start_ptr);
196-
payload.gc_offsets.extend(gc_offsets);
196+
append_gc_offsets(iseq, &gc_offsets);
197197
Some((start_ptr, jit.branch_iseqs))
198198
} else {
199199
None
@@ -999,7 +999,7 @@ fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard
999999

10001000
/// Compile an identity check with a side exit
10011001
fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, expected: VALUE, state: &FrameState) -> Option<lir::Opnd> {
1002-
asm.cmp(val, Opnd::UImm(expected.into()));
1002+
asm.cmp(val, Opnd::Value(expected));
10031003
asm.jnz(side_exit(jit, state, GuardBitEquals(expected))?);
10041004
Some(val)
10051005
}

zjit/src/gc.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,23 @@ pub extern "C" fn rb_zjit_iseq_mark(payload: *mut c_void) {
9090
}
9191
}
9292

93+
/// Append a set of gc_offsets to the iseq's payload
94+
pub fn append_gc_offsets(iseq: IseqPtr, offsets: &Vec<CodePtr>) {
95+
let payload = get_or_create_iseq_payload(iseq);
96+
payload.gc_offsets.extend(offsets);
97+
98+
// Call writebarrier on each newly added value
99+
let cb = ZJITState::get_code_block();
100+
for &offset in offsets.iter() {
101+
let value_ptr: *const u8 = offset.raw_ptr(cb);
102+
let value_ptr = value_ptr as *const VALUE;
103+
unsafe {
104+
let object = value_ptr.read_unaligned();
105+
rb_gc_writebarrier(iseq.into(), object);
106+
}
107+
}
108+
}
109+
93110
/// GC callback for updating GC objects in the per-iseq payload.
94111
/// This is a mirror of [rb_zjit_iseq_mark].
95112
#[unsafe(no_mangle)]

zjit/src/profile.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,10 @@ fn profile_operands(profiler: &mut Profiler, profile: &mut IseqProfile, n: usize
8888
for i in 0..n {
8989
let opnd_type = Type::from_value(profiler.peek_at_stack((n - i - 1) as isize));
9090
types[i] = types[i].union(opnd_type);
91+
if let Some(object) = types[i].gc_object() {
92+
unsafe { rb_gc_writebarrier(profiler.iseq.into(), object) };
93+
}
9194
}
92-
// In the loop above, we probably added a new reference to the profile through
93-
// the VALUE in Type. It's messy and relatively slow to conditionally run a
94-
// write barrier for each Type, so just remember to re-mark the iseq.
95-
unsafe { rb_gc_writebarrier_remember(profiler.iseq.into()) };
9695
}
9796

9897
#[derive(Debug)]

0 commit comments

Comments
 (0)