Skip to content

Commit 809a9a9

Browse files
authored
ZJIT: Count exits coming from jit_exception (ruby#14428)
1 parent 45e1839 commit 809a9a9

File tree

6 files changed

+49
-17
lines changed

6 files changed

+49
-17
lines changed

vm.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ jit_compile(rb_execution_context_t *ec)
445445

446446
// At call-threshold, compile the ISEQ with ZJIT.
447447
if (body->jit_entry_calls == rb_zjit_call_threshold) {
448-
rb_zjit_compile_iseq(iseq, ec, false);
448+
rb_zjit_compile_iseq(iseq, false);
449449
}
450450
}
451451
#endif
@@ -493,8 +493,25 @@ jit_compile_exception(rb_execution_context_t *ec)
493493
const rb_iseq_t *iseq = ec->cfp->iseq;
494494
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
495495

496-
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
496+
#if USE_ZJIT
497+
if (body->jit_exception == NULL && rb_zjit_enabled_p) {
498+
body->jit_exception_calls++;
499+
500+
// At profile-threshold, rewrite some of the YARV instructions
501+
// to zjit_* instructions to profile these instructions.
502+
if (body->jit_exception_calls == rb_zjit_profile_threshold) {
503+
rb_zjit_profile_enable(iseq);
504+
}
505+
506+
// At call-threshold, compile the ISEQ with ZJIT.
507+
if (body->jit_exception_calls == rb_zjit_call_threshold) {
508+
rb_zjit_compile_iseq(iseq, true);
509+
}
510+
}
511+
#endif
512+
497513
#if USE_YJIT
514+
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
498515
if (body->jit_exception == NULL && rb_yjit_enabled_p) {
499516
body->jit_exception_calls++;
500517
if (body->jit_exception_calls == rb_yjit_call_threshold) {

yjit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit
655655
else {
656656
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
657657
}
658-
}
658+
}
659659
}
660660

661661
// GC root for interacting with the GC

zjit.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,22 @@ rb_zjit_reserve_addr_space(uint32_t mem_size)
159159
void rb_zjit_profile_disable(const rb_iseq_t *iseq);
160160

161161
void
162-
rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception)
162+
rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception)
163163
{
164164
RB_VM_LOCKING() {
165165
rb_vm_barrier();
166166

167167
// Compile a block version starting at the current instruction
168-
uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t *iseq, rb_execution_context_t *ec); // defined in Rust
169-
uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, ec);
168+
uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t *iseq, bool jit_exception); // defined in Rust
169+
uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, jit_exception);
170170

171-
// TODO: support jit_exception
172-
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
173-
}
171+
if (jit_exception) {
172+
iseq->body->jit_exception = (rb_jit_func_t)code_ptr;
173+
}
174+
else {
175+
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
176+
}
177+
}
174178
}
175179

176180
extern VALUE *rb_vm_base_ptr(struct rb_control_frame_struct *cfp);

zjit.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
extern bool rb_zjit_enabled_p;
1414
extern uint64_t rb_zjit_call_threshold;
1515
extern uint64_t rb_zjit_profile_threshold;
16-
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
16+
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception);
1717
void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec);
1818
void rb_zjit_profile_enable(const rb_iseq_t *iseq);
1919
void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
@@ -26,7 +26,7 @@ void rb_zjit_before_ractor_spawn(void);
2626
void rb_zjit_tracing_invalidate_all(void);
2727
#else
2828
#define rb_zjit_enabled_p false
29-
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
29+
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception) {}
3030
static inline void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec) {}
3131
static inline void rb_zjit_profile_enable(const rb_iseq_t *iseq) {}
3232
static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}

zjit/src/codegen.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ impl JITState {
6565
}
6666
}
6767

68-
/// CRuby API to compile a given ISEQ
68+
/// CRuby API to compile a given ISEQ.
69+
/// If jit_exception is true, compile JIT code for handling exceptions.
70+
/// See jit_compile_exception() for details.
6971
#[unsafe(no_mangle)]
70-
pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *const u8 {
72+
pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, jit_exception: bool) -> *const u8 {
7173
// Do not test the JIT code in HIR tests
7274
if cfg!(test) {
7375
return std::ptr::null();
@@ -77,11 +79,12 @@ pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *co
7779
// with_vm_lock() does nothing if the program doesn't use Ractors.
7880
with_vm_lock(src_loc!(), || {
7981
let cb = ZJITState::get_code_block();
80-
let mut code_ptr = with_time_stat(compile_time_ns, || gen_iseq_entry_point(cb, iseq));
82+
let mut code_ptr = with_time_stat(compile_time_ns, || gen_iseq_entry_point(cb, iseq, jit_exception));
8183

8284
if let Err(err) = &code_ptr {
83-
// Assert that the ISEQ compiles if RubyVM::ZJIT.assert_compiles is enabled
84-
if ZJITState::assert_compiles_enabled() {
85+
// Assert that the ISEQ compiles if RubyVM::ZJIT.assert_compiles is enabled.
86+
// We assert only `jit_exception: false` cases until we support exception handlers.
87+
if ZJITState::assert_compiles_enabled() && !jit_exception {
8588
let iseq_location = iseq_get_location(iseq, 0);
8689
panic!("Failed to compile: {iseq_location}");
8790
}
@@ -102,7 +105,12 @@ pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, _ec: EcPtr) -> *co
102105
}
103106

104107
/// Compile an entry point for a given ISEQ
105-
fn gen_iseq_entry_point(cb: &mut CodeBlock, iseq: IseqPtr) -> Result<CodePtr, CompileError> {
108+
fn gen_iseq_entry_point(cb: &mut CodeBlock, iseq: IseqPtr, jit_exception: bool) -> Result<CodePtr, CompileError> {
109+
// We don't support exception handlers yet
110+
if jit_exception {
111+
return Err(CompileError::ExceptionHandler);
112+
}
113+
106114
// Compile ISEQ into High-level IR
107115
let function = compile_iseq(iseq).inspect_err(|_| {
108116
incr_counter!(failed_iseq_count);

zjit/src/stats.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ make_counters! {
116116

117117
// compile_error_: Compile error reasons
118118
compile_error_iseq_stack_too_large,
119+
compile_error_exception_handler,
119120
compile_error_out_of_memory,
120121
compile_error_register_spill_on_ccall,
121122
compile_error_register_spill_on_alloc,
@@ -180,6 +181,7 @@ pub fn exit_counter_ptr_for_call_type(call_type: crate::hir::CallType) -> *mut u
180181
#[derive(Clone, Debug, PartialEq)]
181182
pub enum CompileError {
182183
IseqStackTooLarge,
184+
ExceptionHandler,
183185
OutOfMemory,
184186
RegisterSpillOnAlloc,
185187
RegisterSpillOnCCall,
@@ -194,6 +196,7 @@ pub fn exit_counter_for_compile_error(compile_error: &CompileError) -> Counter {
194196
use crate::stats::Counter::*;
195197
match compile_error {
196198
IseqStackTooLarge => compile_error_iseq_stack_too_large,
199+
ExceptionHandler => compile_error_exception_handler,
197200
OutOfMemory => compile_error_out_of_memory,
198201
RegisterSpillOnAlloc => compile_error_register_spill_on_alloc,
199202
RegisterSpillOnCCall => compile_error_register_spill_on_ccall,

0 commit comments

Comments
 (0)