Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion test/.excludes-zjit/TestKeywordArguments.rb

This file was deleted.

11 changes: 10 additions & 1 deletion test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,14 @@ def test_require_rubygems_with_auto_compact
}, call_threshold: 2
end

def test_stats
assert_runs 'true', %q{
def test = 1
test
RubyVM::ZJIT.stats[:zjit_insns_count] > 0
}, stats: true
end

def test_zjit_option_uses_array_each_in_ruby
omit 'ZJIT wrongly compiles Array#each, so it is disabled for now'
assert_runs '"<internal:array>"', %q{
Expand Down Expand Up @@ -1414,12 +1422,13 @@ def assert_runs(expected, test_script, insns: [], assert_compiles: false, **opts
end

# Run a Ruby process with ZJIT options and a pipe for writing test results
def eval_with_jit(script, call_threshold: 1, num_profiles: 1, timeout: 1000, pipe_fd:, debug: true)
def eval_with_jit(script, call_threshold: 1, num_profiles: 1, stats: false, debug: true, timeout: 1000, pipe_fd:)
args = [
"--disable-gems",
"--zjit-call-threshold=#{call_threshold}",
"--zjit-num-profiles=#{num_profiles}",
]
args << "--zjit-stats" if stats
args << "--zjit-debug" if debug
args << "-e" << script_shell_encode(script)
pipe_r, pipe_w = IO.pipe
Expand Down
8 changes: 5 additions & 3 deletions vm_method.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,19 @@ rb_vm_cc_table_create(size_t capa)
static enum rb_id_table_iterator_result
vm_cc_table_dup_i(ID key, VALUE old_ccs_ptr, void *data)
{
VALUE new_table = (VALUE)data;
struct rb_class_cc_entries *old_ccs = (struct rb_class_cc_entries *)old_ccs_ptr;
size_t memsize = vm_ccs_alloc_size(old_ccs->capa);
struct rb_class_cc_entries *new_ccs = ruby_xmalloc(memsize);
struct rb_class_cc_entries *new_ccs = ruby_xcalloc(1, memsize);
rb_managed_id_table_insert(new_table, key, (VALUE)new_ccs);

memcpy(new_ccs, old_ccs, memsize);

#if VM_CHECK_MODE > 0
new_ccs->debug_sig = ~(VALUE)new_ccs;
#endif

VALUE new_table = (VALUE)data;
rb_managed_id_table_insert(new_table, key, (VALUE)new_ccs);
RB_OBJ_WRITTEN(new_table, Qundef, (VALUE)new_ccs->cme);
for (int index = 0; index < new_ccs->len; index++) {
RB_OBJ_WRITTEN(new_table, Qundef, new_ccs->entries[index].cc);
}
Expand Down
37 changes: 37 additions & 0 deletions zjit/src/asm/arm64/inst/mov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use super::super::arg::Sf;

/// Which operation is being performed.
enum Op {
/// A movn operation which inverts the immediate and zeroes out the other bits.
MOVN = 0b00,

/// A movz operation which zeroes out the other bits.
MOVZ = 0b10,

Expand Down Expand Up @@ -61,6 +64,12 @@ impl Mov {
Self { rd, imm16, hw: hw.into(), op: Op::MOVK, sf: num_bits.into() }
}

/// MOVN
/// <https://developer.arm.com/documentation/ddi0602/2025-06/Base-Instructions/MOVN--Move-wide-with-NOT->
pub fn movn(rd: u8, imm16: u16, hw: u8, num_bits: u8) -> Self {
Self { rd, imm16, hw: hw.into(), op: Op::MOVN, sf: num_bits.into() }
}

/// MOVZ
/// <https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/MOVZ--Move-wide-with-zero-?lang=en>
pub fn movz(rd: u8, imm16: u16, hw: u8, num_bits: u8) -> Self {
Expand Down Expand Up @@ -104,6 +113,34 @@ mod tests {
assert_eq!(0xf2800f60, result);
}

#[test]
fn test_movn_unshifted() {
let inst = Mov::movn(0, 123, 0, 64);
let result: u32 = inst.into();
assert_eq!(0x92800f60, result);
}

#[test]
fn test_movn_shifted_16() {
let inst = Mov::movn(0, 123, 16, 64);
let result: u32 = inst.into();
assert_eq!(0x92a00f60, result);
}

#[test]
fn test_movn_shifted_32() {
let inst = Mov::movn(0, 123, 32, 64);
let result: u32 = inst.into();
assert_eq!(0x92c00f60, result);
}

#[test]
fn test_movn_shifted_48() {
let inst = Mov::movn(0, 123, 48, 64);
let result: u32 = inst.into();
assert_eq!(0x92e00f60, result);
}

#[test]
fn test_movk_shifted_16() {
let inst = Mov::movk(0, 123, 16, 64);
Expand Down
20 changes: 20 additions & 0 deletions zjit/src/asm/arm64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,21 @@ pub fn movk(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
cb.write_bytes(&bytes);
}

/// MOVN - load a register with the complement of a shifted then zero extended 16-bit immediate
/// <https://developer.arm.com/documentation/ddi0602/2025-06/Base-Instructions/MOVN--Move-wide-with-NOT->
pub fn movn(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
let bytes: [u8; 4] = match (rd, imm16) {
(A64Opnd::Reg(rd), A64Opnd::UImm(imm16)) => {
assert!(uimm_fits_bits(imm16, 16), "The immediate operand must be 16 bits or less.");

Mov::movn(rd.reg_no, imm16 as u16, shift, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to movn instruction.")
};

cb.write_bytes(&bytes);
}

/// MOVZ - move a 16 bit immediate into a register, zero the other bits
pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
let bytes: [u8; 4] = match (rd, imm16) {
Expand Down Expand Up @@ -1543,6 +1558,11 @@ mod tests {
check_bytes("600fa0f2", |cb| movk(cb, X0, A64Opnd::new_uimm(123), 16));
}

#[test]
fn test_movn() {
check_bytes("600fa092", |cb| movn(cb, X0, A64Opnd::new_uimm(123), 16));
}

#[test]
fn test_movz() {
check_bytes("600fa0d2", |cb| movz(cb, X0, A64Opnd::new_uimm(123), 16));
Expand Down
Loading