Skip to content

Commit e5c39e6

Browse files
committed
ZJIT: Implement SingleRactorMode invalidation
1 parent d5e7e88 commit e5c39e6

4 files changed

Lines changed: 47 additions & 5 deletions

File tree

ractor.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "internal/thread.h"
2020
#include "variable.h"
2121
#include "yjit.h"
22+
#include "zjit.h"
2223

2324
VALUE rb_cRactor;
2425
static VALUE rb_cRactorSelector;
@@ -511,6 +512,7 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
511512
r->debug = cr->debug;
512513

513514
rb_yjit_before_ractor_spawn();
515+
rb_zjit_before_ractor_spawn();
514516
rb_thread_create_ractor(r, args, block);
515517

516518
RB_GC_GUARD(rv);

zjit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq);
2222
void rb_zjit_constant_state_changed(ID id);
2323
void rb_zjit_iseq_mark(void *payload);
2424
void rb_zjit_iseq_update_references(void *payload);
25+
void rb_zjit_before_ractor_spawn(void);
2526
#else
2627
#define rb_zjit_enabled_p false
2728
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
@@ -31,6 +32,7 @@ static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_ope
3132
static inline void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme) {}
3233
static inline void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq) {}
3334
static inline void rb_zjit_constant_state_changed(ID id) {}
35+
static inline void rb_zjit_before_ractor_spawn(void) {}
3436
#endif // #if USE_YJIT
3537

3638
#endif // #ifndef ZJIT_H

zjit/src/codegen.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::ffi::{c_int, c_void};
44

55
use crate::asm::Label;
66
use crate::backend::current::{Reg, ALLOC_REGS};
7-
use crate::invariants::{track_bop_assumption, track_cme_assumption, track_stable_constant_names_assumption};
7+
use crate::invariants::{track_bop_assumption, track_cme_assumption, track_single_ractor_assumption, track_stable_constant_names_assumption};
88
use crate::gc::{get_or_create_iseq_payload, append_gc_offsets};
99
use crate::state::ZJITState;
1010
use crate::stats::{counter_ptr, Counter};
@@ -542,9 +542,9 @@ fn gen_patch_point(jit: &mut JITState, asm: &mut Assembler, invariant: &Invarian
542542
let side_exit_ptr = cb.resolve_label(label);
543543
track_stable_constant_names_assumption(idlist, code_ptr, side_exit_ptr);
544544
}
545-
_ => {
546-
debug!("ZJIT: gen_patch_point: unimplemented invariant {invariant:?}");
547-
return;
545+
Invariant::SingleRactorMode => {
546+
let side_exit_ptr = cb.resolve_label(label);
547+
track_single_ractor_assumption(code_ptr, side_exit_ptr);
548548
}
549549
}
550550
});

zjit/src/invariants.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::{HashMap, HashSet}};
1+
use std::{collections::{HashMap, HashSet}, mem};
22

33
use crate::{backend::lir::{asm_comment, Assembler}, cruby::{rb_callable_method_entry_t, ruby_basic_operators, src_loc, with_vm_lock, IseqPtr, RedefinitionFlag, ID}, hir::Invariant, options::debug, state::{zjit_enabled_p, ZJITState}, virtualmem::CodePtr};
44

@@ -26,6 +26,9 @@ pub struct Invariants {
2626

2727
/// Map from constant ID to patch points that assume the constant hasn't been redefined
2828
constant_state_patch_points: HashMap<ID, HashSet<Jump>>,
29+
30+
/// Set of patch points that assume that the interpreter is running with only one ractor
31+
single_ractor_patch_points: HashSet<Jump>,
2932
}
3033

3134
/// Called when a basic operator is redefined. Note that all the blocks assuming
@@ -200,3 +203,38 @@ pub extern "C" fn rb_zjit_constant_state_changed(id: ID) {
200203
}
201204
});
202205
}
206+
207+
/// Track that JIT code for a patch point that assumes that the interpreter is running with only one ractor
208+
pub fn track_single_ractor_assumption(patch_point_ptr: CodePtr, side_exit_ptr: CodePtr) {
209+
let invariants = ZJITState::get_invariants();
210+
invariants.single_ractor_patch_points.insert(Jump {
211+
from: patch_point_ptr,
212+
to: side_exit_ptr,
213+
});
214+
}
215+
216+
/// Callback for then Ruby is about to spawn a ractor. In that case we need to
217+
/// invalidate every block that is assuming single ractor mode.
218+
#[unsafe(no_mangle)]
219+
pub extern "C" fn rb_zjit_before_ractor_spawn() {
220+
// If ZJIT isn't enabled, do nothing
221+
if !zjit_enabled_p() {
222+
return;
223+
}
224+
225+
with_vm_lock(src_loc!(), || {
226+
// Clear the set of blocks inside Invariants
227+
let jumps = mem::take(&mut ZJITState::get_invariants().single_ractor_patch_points);
228+
229+
// Invalidate the blocks
230+
for jump in &jumps {
231+
let cb = ZJITState::get_code_block();
232+
cb.with_write_ptr(jump.from, |cb| {
233+
let mut asm = Assembler::new();
234+
asm_comment!(asm, "Single ractor mode is invalidated");
235+
asm.jmp(jump.to.into());
236+
asm.compile(cb).expect("can write existing code");
237+
});
238+
}
239+
});
240+
}

0 commit comments

Comments
 (0)