YJIT: Fix getconstant exits after opt_ltlt fusion (#10903)

Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
This commit is contained in:
Takashi Kokubun 2024-06-04 07:17:40 -07:00 коммит произвёл GitHub
Родитель a8c1ef6a60
Коммит a2147eb694
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 30 добавлений и 13 удалений

Просмотреть файл

@ -4813,6 +4813,15 @@ assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
tests
}
# test integer left shift fusion followed by opt_getconstant_path
assert_equal '33', %q{
def test(a)
(a << 5) | (Object; a)
end
test(1)
}
# test String#stebyte with arguments that need conversion
assert_equal "abc", %q{
str = +"a00"

Просмотреть файл

@ -30,7 +30,6 @@ pub use crate::virtualmem::CodePtr;
/// Status returned by code generation functions
#[derive(PartialEq, Debug)]
enum CodegenStatus {
SkipNextInsn,
KeepCompiling,
EndBlock,
}
@ -197,6 +196,13 @@ impl JITState {
self.insn_idx + insn_len(self.get_opcode()) as u16
}
/// Get the index of the next instruction of the next instruction
fn next_next_insn_idx(&self) -> u16 {
let next_pc = unsafe { rb_iseq_pc_at_idx(self.iseq, self.next_insn_idx().into()) };
let next_opcode: usize = unsafe { rb_iseq_opcode_at_pc(self.iseq, next_pc) }.try_into().unwrap();
self.next_insn_idx() + insn_len(next_opcode) as u16
}
// Check if we are compiling the instruction at the stub PC
// Meaning we are compiling the instruction that is next to execute
pub fn at_current_insn(&self) -> bool {
@ -1098,7 +1104,16 @@ fn jump_to_next_insn(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> Option<()> {
) -> Option<CodegenStatus> {
end_block_with_jump(jit, asm, ocb, jit.next_insn_idx())
}
fn end_block_with_jump(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
continuation_insn_idx: u16,
) -> Option<CodegenStatus> {
// Reset the depth since in current usages we only ever jump to
// chain_depth > 0 from the same instruction.
let mut reset_depth = asm.ctx;
@ -1106,20 +1121,20 @@ fn jump_to_next_insn(
let jump_block = BlockId {
iseq: jit.iseq,
idx: jit.next_insn_idx(),
idx: continuation_insn_idx,
};
// We are at the end of the current instruction. Record the boundary.
if jit.record_boundary_patch_point {
jit.record_boundary_patch_point = false;
let exit_pc = unsafe { jit.pc.offset(insn_len(jit.opcode).try_into().unwrap()) };
let exit_pc = unsafe { rb_iseq_pc_at_idx(jit.iseq, continuation_insn_idx.into())};
let exit_pos = gen_outlined_exit(exit_pc, &reset_depth, ocb);
record_global_inval_patch(asm, exit_pos?);
}
// Generate the jump instruction
gen_direct_jump(jit, &reset_depth, jump_block, asm);
Some(())
Some(EndBlock)
}
// Compile a sequence of bytecode instructions for a given basic block version.
@ -1283,13 +1298,6 @@ pub fn gen_single_block(
// Move to the next instruction to compile
insn_idx += insn_len(opcode) as u16;
// Move past next instruction when instructed
if status == Some(SkipNextInsn) {
let next_pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx.into()) };
let next_opcode: usize = unsafe { rb_iseq_opcode_at_pc(iseq, next_pc) }.try_into().unwrap();
insn_idx += insn_len(next_opcode) as u16;
}
// If the instruction terminates this block
if status == Some(EndBlock) {
break;
@ -1519,7 +1527,7 @@ fn fuse_putobject_opt_ltlt(
asm.stack_pop(1);
fixnum_left_shift_body(asm, lhs, shift_amt as u64);
return Some(SkipNextInsn);
return end_block_with_jump(jit, asm, ocb, jit.next_next_insn_idx());
}
return None;
}