ZJIT: Fix "memory operand with non-register base" (#14153)

This commit is contained in:
Takashi Kokubun 2025-08-08 11:24:39 -07:00 committed by GitHub
parent 8eb26ebf91
commit eb931a09c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 2 deletions

View file

@ -148,6 +148,18 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 2
end
def test_send_on_heap_object_in_spilled_arg
# This leads to a register spill, so not using `assert_compiles`
assert_runs 'Hash', %q{
def entry(a1, a2, a3, a4, a5, a6, a7, a8, a9)
a9.itself.class
end
entry(1, 2, 3, 4, 5, 6, 7, 8, {}) # profile
entry(1, 2, 3, 4, 5, 6, 7, 8, {})
}, call_threshold: 2
end
def test_invokebuiltin
omit 'Test fails at the moment due to not handling optional parameters'
assert_compiles '["."]', %q{

View file

@ -111,7 +111,7 @@ impl Opnd
})
},
_ => unreachable!("memory operand with non-register base")
_ => unreachable!("memory operand with non-register base: {base:?}")
}
}

View file

@ -1088,9 +1088,15 @@ fn gen_guard_type(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, guard
} else if let Some(expected_class) = guard_type.runtime_exact_ruby_class() {
asm_comment!(asm, "guard exact class for non-immediate types");
let side_exit = side_exit(jit, state, GuardType(guard_type))?;
// If val isn't in a register, load it to use it as the base of Opnd::mem later.
// TODO: Max thinks codegen should not care about the shapes of the operands except to create them. (Shopify/ruby#685)
let val = match val {
Opnd::Reg(_) | Opnd::VReg { .. } => val,
_ => asm.load(val),
};
// Check if it's a special constant
let side_exit = side_exit(jit, state, GuardType(guard_type))?;
asm.test(val, (RUBY_IMMEDIATE_MASK as u64).into());
asm.jnz(side_exit.clone());