summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <[email protected]>2024-11-19 18:02:26 -0500
committerAlan Wu <[email protected]>2024-11-20 10:06:14 -0500
commit199877d2583a5c4b9553b9c197aca39b46ba77e6 ()
tree94eaa38333663547e98d0608ca484777b444226e
parent2df2e868bc21e39ac493cebac1c981f1ed279010 (diff)
YJIT: Abandon block when gen_outlined_exit() fails
When CodeBlock::set_page fails (part of next_page(), see their docs for exact conditions), it can cause gen_outlined_exit() to fail while there is still plenty of memory available. Previously, this can have YJIT running incomplete code due to taking the early return in end_block_with_jump() that manifested as crashes with SIGILL. Add and use a wrapper with error handling.
Notes: Merged: https://.com/ruby/ruby/pull/12124
-rw-r--r--yjit/src/codegen.rs21
1 files changed, 18 insertions, 3 deletions
@@ -223,6 +223,17 @@ impl<'a> JITState<'a> {
}
}
/// Return true if the current ISEQ could escape an environment.
///
/// As of vm_push_frame(), EP is always equal to BP. However, after pushing
@@ -879,6 +890,10 @@ fn gen_exit(exit_pc: *mut VALUE, asm: &mut Assembler) {
/// moment, so there is one unique side exit for each context. Note that
/// it's incorrect to jump to the side exit after any ctx stack push operations
/// since they change the logic required for reconstructing interpreter state.
pub fn gen_outlined_exit(exit_pc: *mut VALUE, num_locals: u32, ctx: &Context, ocb: &mut OutlinedCb) -> Option<CodePtr> {
let mut cb = ocb.unwrap();
let mut asm = Assembler::new(num_locals);
@@ -943,7 +958,7 @@ pub fn jit_ensure_block_entry_exit(jit: &mut JITState, asm: &mut Assembler) -> O
jit.block_entry_exit = Some(entry_exit?);
} else {
let block_entry_pc = unsafe { rb_iseq_pc_at_idx(jit.iseq, jit.starting_insn_idx.into()) };
- jit.block_entry_exit = Some(gen_outlined_exit(block_entry_pc, jit.num_locals(), block_starting_context, jit.get_ocb())?);
}
Some(())
@@ -1201,7 +1216,7 @@ fn end_block_with_jump(
if jit.record_boundary__point {
jit.record_boundary__point = false;
let exit_pc = unsafe { rb_iseq_pc_at_idx(jit.iseq, continuation_insn_idx.into())};
- let exit_pos = gen_outlined_exit(exit_pc, jit.num_locals(), &reset_depth, jit.get_ocb());
record_global_inval_(asm, exit_pos?);
}
@@ -1310,7 +1325,7 @@ pub fn gen_single_block(
// If previous instruction requested to record the boundary
if jit.record_boundary__point {
// Generate an exit to this instruction and record it
- let exit_pos = gen_outlined_exit(jit.pc, jit.num_locals(), &asm.ctx, jit.get_ocb()).ok_or(())?;
record_global_inval_(&mut asm, exit_pos);
jit.record_boundary__point = false;
}