From a54351f98ce68999ed798a68c8ea58c5abb71467 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 19 Sep 2025 07:08:13 -0700 Subject: [PATCH 01/22] ZJIT: Test disasm with insta (#14602) --- zjit/src/asm/arm64/mod.rs | 403 +++++++++++---- zjit/src/asm/mod.rs | 19 + zjit/src/asm/x86_64/tests.rs | 890 ++++++++++++++++++++++++--------- zjit/src/assertions.rs | 21 - zjit/src/backend/arm64/mod.rs | 81 +-- zjit/src/backend/x86_64/mod.rs | 206 +++++--- zjit/src/lib.rs | 2 - 7 files changed, 1155 insertions(+), 467 deletions(-) delete mode 100644 zjit/src/assertions.rs diff --git a/zjit/src/asm/arm64/mod.rs b/zjit/src/asm/arm64/mod.rs index 63ac7823f18d98..d7e48d6c0cf57e 100644 --- a/zjit/src/asm/arm64/mod.rs +++ b/zjit/src/asm/arm64/mod.rs @@ -1212,13 +1212,12 @@ fn cbz_cbnz(num_bits: u8, op: bool, offset: InstructionOffset, rt: u8) -> [u8; 4 #[cfg(test)] mod tests { use super::*; - use crate::assertions::assert_disasm; + use insta::assert_snapshot; - /// Check that the bytes for an instruction sequence match a hex string - fn check_bytes(bytes: &str, run: R) where R: FnOnce(&mut super::CodeBlock) { + fn compile(run: R) -> CodeBlock where R: FnOnce(&mut super::CodeBlock) { let mut cb = super::CodeBlock::new_dummy(); run(&mut cb); - assert_eq!(format!("{:x}", cb), bytes); + cb } #[test] @@ -1246,94 +1245,130 @@ mod tests { #[test] fn test_add_reg() { - check_bytes("2000028b", |cb| add(cb, X0, X1, X2)); + let cb = compile(|cb| add(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, x2"); + assert_snapshot!(cb.string(), @"2000028b"); } #[test] fn test_add_uimm() { - check_bytes("201c0091", |cb| add(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_add_imm_positive() { - check_bytes("201c0091", |cb| add(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_add_imm_negative() { - check_bytes("201c00d1", |cb| add(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_adds_reg() { - check_bytes("200002ab", |cb| adds(cb, X0, X1, X2)); + let cb = compile(|cb| adds(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002ab"); } #[test] fn test_adds_uimm() { - check_bytes("201c00b1", |cb| adds(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_adds_imm_positive() { - check_bytes("201c00b1", |cb| adds(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_adds_imm_negative() { - check_bytes("201c00f1", |cb| adds(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_adr() { - check_bytes("aa000010", |cb| adr(cb, X10, A64Opnd::new_imm(20))); + let cb = compile(|cb| adr(cb, X10, A64Opnd::new_imm(20))); + assert_snapshot!(cb.disasm(), @" 0x0: adr x10, #0x14"); + assert_snapshot!(cb.string(), @"aa000010"); } #[test] fn test_adrp() { - check_bytes("4a000090", |cb| adrp(cb, X10, A64Opnd::new_imm(0x8000))); + let cb = compile(|cb| adrp(cb, X10, A64Opnd::new_imm(0x8000))); + assert_snapshot!(cb.disasm(), @" 0x0: adrp x10, #0x8000"); + assert_snapshot!(cb.string(), @"4a000090"); } #[test] fn test_and_register() { - check_bytes("2000028a", |cb| and(cb, X0, X1, X2)); + let cb = compile(|cb| and(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, x2"); + assert_snapshot!(cb.string(), @"2000028a"); } #[test] fn test_and_immediate() { - check_bytes("20084092", |cb| and(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| and(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, #7"); + assert_snapshot!(cb.string(), @"20084092"); } #[test] fn test_and_32b_immediate() { - check_bytes("404c0012", |cb| and(cb, W0, W2, A64Opnd::new_uimm(0xfffff))); + let cb = compile(|cb| and(cb, W0, W2, A64Opnd::new_uimm(0xfffff))); + assert_snapshot!(cb.disasm(), @" 0x0: and w0, w2, #0xfffff"); + assert_snapshot!(cb.string(), @"404c0012"); } #[test] fn test_ands_register() { - check_bytes("200002ea", |cb| ands(cb, X0, X1, X2)); + let cb = compile(|cb| ands(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002ea"); } #[test] fn test_ands_immediate() { - check_bytes("200840f2", |cb| ands(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| ands(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, #7"); + assert_snapshot!(cb.string(), @"200840f2"); } #[test] fn test_asr() { - check_bytes("b4fe4a93", |cb| asr(cb, X20, X21, A64Opnd::new_uimm(10))); + let cb = compile(|cb| asr(cb, X20, X21, A64Opnd::new_uimm(10))); + assert_snapshot!(cb.disasm(), @" 0x0: asr x20, x21, #0xa"); + assert_snapshot!(cb.string(), @"b4fe4a93"); } #[test] fn test_bcond() { let offset = InstructionOffset::from_insns(0x100); - check_bytes("01200054", |cb| bcond(cb, Condition::NE, offset)); + let cb = compile(|cb| bcond(cb, Condition::NE, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: b.ne #0x400"); + assert_snapshot!(cb.string(), @"01200054"); } #[test] fn test_b() { let offset = InstructionOffset::from_insns((1 << 25) - 1); - check_bytes("ffffff15", |cb| b(cb, offset)); + let cb = compile(|cb| b(cb, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: b #0x7fffffc"); + assert_snapshot!(cb.string(), @"ffffff15"); } #[test] @@ -1341,7 +1376,7 @@ mod tests { fn test_b_too_big() { // There are 26 bits available let offset = InstructionOffset::from_insns(1 << 25); - check_bytes("", |cb| b(cb, offset)); + compile(|cb| b(cb, offset)); } #[test] @@ -1349,13 +1384,15 @@ mod tests { fn test_b_too_small() { // There are 26 bits available let offset = InstructionOffset::from_insns(-(1 << 25) - 1); - check_bytes("", |cb| b(cb, offset)); + compile(|cb| b(cb, offset)); } #[test] fn test_bl() { let offset = InstructionOffset::from_insns(-(1 << 25)); - check_bytes("00000096", |cb| bl(cb, offset)); + let cb = compile(|cb| bl(cb, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: bl #0xfffffffff8000000"); + assert_snapshot!(cb.string(), @"00000096"); } #[test] @@ -1363,7 +1400,7 @@ mod tests { fn test_bl_too_big() { // There are 26 bits available let offset = InstructionOffset::from_insns(1 << 25); - check_bytes("", |cb| bl(cb, offset)); + compile(|cb| bl(cb, offset)); } #[test] @@ -1371,385 +1408,544 @@ mod tests { fn test_bl_too_small() { // There are 26 bits available let offset = InstructionOffset::from_insns(-(1 << 25) - 1); - check_bytes("", |cb| bl(cb, offset)); + compile(|cb| bl(cb, offset)); } #[test] fn test_blr() { - check_bytes("80023fd6", |cb| blr(cb, X20)); + let cb = compile(|cb| blr(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: blr x20"); + assert_snapshot!(cb.string(), @"80023fd6"); } #[test] fn test_br() { - check_bytes("80021fd6", |cb| br(cb, X20)); + let cb = compile(|cb| br(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: br x20"); + assert_snapshot!(cb.string(), @"80021fd6"); } #[test] fn test_cbz() { let offset = InstructionOffset::from_insns(-1); - check_bytes("e0ffffb4e0ffff34", |cb| { + let cb = compile(|cb| { cbz(cb, X0, offset); cbz(cb, W0, offset); }); + assert_snapshot!(cb.disasm(), @r" + 0x0: cbz x0, #0xfffffffffffffffc + 0x4: cbz w0, #0 + "); + assert_snapshot!(cb.string(), @"e0ffffb4e0ffff34"); } #[test] fn test_cbnz() { let offset = InstructionOffset::from_insns(2); - check_bytes("540000b554000035", |cb| { + let cb = compile(|cb| { cbnz(cb, X20, offset); cbnz(cb, W20, offset); }); + assert_snapshot!(cb.disasm(), @r" + 0x0: cbnz x20, #8 + 0x4: cbnz w20, #0xc + "); + assert_snapshot!(cb.string(), @"540000b554000035"); } #[test] fn test_brk_none() { - check_bytes("00003ed4", |cb| brk(cb, A64Opnd::None)); + let cb = compile(|cb| brk(cb, A64Opnd::None)); + assert_snapshot!(cb.disasm(), @" 0x0: brk #0xf000"); + assert_snapshot!(cb.string(), @"00003ed4"); } #[test] fn test_brk_uimm() { - check_bytes("c00120d4", |cb| brk(cb, A64Opnd::new_uimm(14))); + let cb = compile(|cb| brk(cb, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: brk #0xe"); + assert_snapshot!(cb.string(), @"c00120d4"); } #[test] fn test_cmp_register() { - check_bytes("5f010beb", |cb| cmp(cb, X10, X11)); + let cb = compile(|cb| cmp(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, x11"); + assert_snapshot!(cb.string(), @"5f010beb"); } #[test] fn test_cmp_immediate() { - check_bytes("5f3900f1", |cb| cmp(cb, X10, A64Opnd::new_uimm(14))); + let cb = compile(|cb| cmp(cb, X10, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, #0xe"); + assert_snapshot!(cb.string(), @"5f3900f1"); } #[test] fn test_csel() { - check_bytes("6a018c9a", |cb| csel(cb, X10, X11, X12, Condition::EQ)); + let cb = compile(|cb| csel(cb, X10, X11, X12, Condition::EQ)); + assert_snapshot!(cb.disasm(), @" 0x0: csel x10, x11, x12, eq"); + assert_snapshot!(cb.string(), @"6a018c9a"); } #[test] fn test_eor_register() { - check_bytes("6a010cca", |cb| eor(cb, X10, X11, X12)); + let cb = compile(|cb| eor(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a010cca"); } #[test] fn test_eor_immediate() { - check_bytes("6a0940d2", |cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); + let cb = compile(|cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, #7"); + assert_snapshot!(cb.string(), @"6a0940d2"); } #[test] fn test_eor_32b_immediate() { - check_bytes("29040152", |cb| eor(cb, W9, W1, A64Opnd::new_uimm(0x80000001))); + let cb = compile(|cb| eor(cb, W9, W1, A64Opnd::new_uimm(0x80000001))); + assert_snapshot!(cb.disasm(), @" 0x0: eor w9, w1, #0x80000001"); + assert_snapshot!(cb.string(), @"29040152"); } #[test] fn test_ldaddal() { - check_bytes("8b01eaf8", |cb| ldaddal(cb, X10, X11, X12)); + let cb = compile(|cb| ldaddal(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: ldaddal x10, x11, [x12]"); + assert_snapshot!(cb.string(), @"8b01eaf8"); } #[test] fn test_ldaxr() { - check_bytes("6afd5fc8", |cb| ldaxr(cb, X10, X11)); + let cb = compile(|cb| ldaxr(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: ldaxr x10, [x11]"); + assert_snapshot!(cb.string(), @"6afd5fc8"); } #[test] fn test_ldp() { - check_bytes("8a2d4da9", |cb| ldp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]"); + assert_snapshot!(cb.string(), @"8a2d4da9"); } #[test] fn test_ldp_pre() { - check_bytes("8a2dcda9", |cb| ldp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]!"); + assert_snapshot!(cb.string(), @"8a2dcda9"); } #[test] fn test_ldp_post() { - check_bytes("8a2dcda8", |cb| ldp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12], #0xd0"); + assert_snapshot!(cb.string(), @"8a2dcda8"); } #[test] fn test_ldr() { - check_bytes("6a696cf8", |cb| ldr(cb, X10, X11, X12)); + let cb = compile(|cb| ldr(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, x12]"); + assert_snapshot!(cb.string(), @"6a696cf8"); } #[test] fn test_ldr_literal() { - check_bytes("40010058", |cb| ldr_literal(cb, X0, 10.into())); + let cb = compile(|cb| ldr_literal(cb, X0, 10.into())); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x0, #0x28"); + assert_snapshot!(cb.string(), @"40010058"); } #[test] fn test_ldr_post() { - check_bytes("6a0541f8", |cb| ldr_post(cb, X10, A64Opnd::new_mem(64, X11, 16))); + let cb = compile(|cb| ldr_post(cb, X10, A64Opnd::new_mem(64, X11, 16))); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11], #0x10"); + assert_snapshot!(cb.string(), @"6a0541f8"); } #[test] fn test_ldr_pre() { - check_bytes("6a0d41f8", |cb| ldr_pre(cb, X10, A64Opnd::new_mem(64, X11, 16))); + let cb = compile(|cb| ldr_pre(cb, X10, A64Opnd::new_mem(64, X11, 16))); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, #0x10]!"); + assert_snapshot!(cb.string(), @"6a0d41f8"); } #[test] fn test_ldrh() { - check_bytes("6a194079", |cb| ldrh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]"); + assert_snapshot!(cb.string(), @"6a194079"); } #[test] fn test_ldrh_pre() { - check_bytes("6acd4078", |cb| ldrh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]!"); + assert_snapshot!(cb.string(), @"6acd4078"); } #[test] fn test_ldrh_post() { - check_bytes("6ac54078", |cb| ldrh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11], #0xc"); + assert_snapshot!(cb.string(), @"6ac54078"); } #[test] fn test_ldurh_memory() { - check_bytes("2a004078", |cb| ldurh(cb, W10, A64Opnd::new_mem(64, X1, 0))); - check_bytes("2ab04778", |cb| ldurh(cb, W10, A64Opnd::new_mem(64, X1, 123))); + let cb = compile(|cb| { + ldurh(cb, W10, A64Opnd::new_mem(64, X1, 0)); + ldurh(cb, W10, A64Opnd::new_mem(64, X1, 123)); + }); + assert_snapshot!(cb.disasm(), @r" + 0x0: ldurh w10, [x1] + 0x4: ldurh w10, [x1, #0x7b] + "); + assert_snapshot!(cb.string(), @"2a0040782ab04778"); } #[test] fn test_ldur_memory() { - check_bytes("20b047f8", |cb| ldur(cb, X0, A64Opnd::new_mem(64, X1, 123))); + let cb = compile(|cb| ldur(cb, X0, A64Opnd::new_mem(64, X1, 123))); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1, #0x7b]"); + assert_snapshot!(cb.string(), @"20b047f8"); } #[test] fn test_ldur_register() { - check_bytes("200040f8", |cb| ldur(cb, X0, X1)); + let cb = compile(|cb| ldur(cb, X0, X1)); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1]"); + assert_snapshot!(cb.string(), @"200040f8"); } #[test] fn test_ldursw() { - check_bytes("6ab187b8", |cb| ldursw(cb, X10, A64Opnd::new_mem(64, X11, 123))); + let cb = compile(|cb| ldursw(cb, X10, A64Opnd::new_mem(64, X11, 123))); + assert_snapshot!(cb.disasm(), @" 0x0: ldursw x10, [x11, #0x7b]"); + assert_snapshot!(cb.string(), @"6ab187b8"); } #[test] fn test_lsl() { - check_bytes("6ac572d3", |cb| lsl(cb, X10, X11, A64Opnd::new_uimm(14))); + let cb = compile(|cb| lsl(cb, X10, X11, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: lsl x10, x11, #0xe"); + assert_snapshot!(cb.string(), @"6ac572d3"); } #[test] fn test_lsr() { - check_bytes("6afd4ed3", |cb| lsr(cb, X10, X11, A64Opnd::new_uimm(14))); + let cb = compile(|cb| lsr(cb, X10, X11, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: lsr x10, x11, #0xe"); + assert_snapshot!(cb.string(), @"6afd4ed3"); } #[test] fn test_mov_registers() { - check_bytes("ea030baa", |cb| mov(cb, X10, X11)); + let cb = compile(|cb| mov(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x10, x11"); + assert_snapshot!(cb.string(), @"ea030baa"); } #[test] fn test_mov_immediate() { - check_bytes("eaf300b2", |cb| mov(cb, X10, A64Opnd::new_uimm(0x5555555555555555))); + let cb = compile(|cb| mov(cb, X10, A64Opnd::new_uimm(0x5555555555555555))); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, xzr, #0x5555555555555555"); + assert_snapshot!(cb.string(), @"eaf300b2"); } #[test] fn test_mov_32b_immediate() { - check_bytes("ea070132", |cb| mov(cb, W10, A64Opnd::new_uimm(0x80000001))); + let cb = compile(|cb| mov(cb, W10, A64Opnd::new_uimm(0x80000001))); + assert_snapshot!(cb.disasm(), @" 0x0: mov w10, #-0x7fffffff"); + assert_snapshot!(cb.string(), @"ea070132"); } #[test] fn test_mov_into_sp() { - check_bytes("1f000091", |cb| mov(cb, X31, X0)); + let cb = compile(|cb| mov(cb, X31, X0)); + assert_snapshot!(cb.disasm(), @" 0x0: mov sp, x0"); + assert_snapshot!(cb.string(), @"1f000091"); } #[test] fn test_mov_from_sp() { - check_bytes("e0030091", |cb| mov(cb, X0, X31)); + let cb = compile(|cb| mov(cb, X0, X31)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, sp"); + assert_snapshot!(cb.string(), @"e0030091"); } #[test] fn test_movk() { - check_bytes("600fa0f2", |cb| movk(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movk(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: movk x0, #0x7b, lsl #16"); + assert_snapshot!(cb.string(), @"600fa0f2"); } #[test] fn test_movn() { - check_bytes("600fa092", |cb| movn(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movn(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #-0x7b0001"); + assert_snapshot!(cb.string(), @"600fa092"); } #[test] fn test_movz() { - check_bytes("600fa0d2", |cb| movz(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movz(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #0x7b0000"); + assert_snapshot!(cb.string(), @"600fa0d2"); } #[test] fn test_mrs() { - check_bytes("0a423bd5", |cb| mrs(cb, X10, SystemRegister::NZCV)); + let cb = compile(|cb| mrs(cb, X10, SystemRegister::NZCV)); + assert_snapshot!(cb.disasm(), @" 0x0: mrs x10, nzcv"); + assert_snapshot!(cb.string(), @"0a423bd5"); } #[test] fn test_msr() { - check_bytes("0a421bd5", |cb| msr(cb, SystemRegister::NZCV, X10)); + let cb = compile(|cb| msr(cb, SystemRegister::NZCV, X10)); + assert_snapshot!(cb.disasm(), @" 0x0: msr nzcv, x10"); + assert_snapshot!(cb.string(), @"0a421bd5"); } #[test] fn test_mul() { - check_bytes("6a7d0c9b", |cb| mul(cb, X10, X11, X12)); + let cb = compile(|cb| mul(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: mul x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a7d0c9b"); } #[test] fn test_mvn() { - check_bytes("ea032baa", |cb| mvn(cb, X10, X11)); + let cb = compile(|cb| mvn(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: mvn x10, x11"); + assert_snapshot!(cb.string(), @"ea032baa"); } #[test] fn test_nop() { - check_bytes("1f2003d5", nop); + let cb = compile(nop); + assert_snapshot!(cb.disasm(), @" 0x0: nop"); + assert_snapshot!(cb.string(), @"1f2003d5"); } #[test] fn test_orn() { - check_bytes("6a012caa", |cb| orn(cb, X10, X11, X12)); + let cb = compile(|cb| orn(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: orn x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a012caa"); } #[test] fn test_orr_register() { - check_bytes("6a010caa", |cb| orr(cb, X10, X11, X12)); + let cb = compile(|cb| orr(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a010caa"); } #[test] fn test_orr_immediate() { - check_bytes("6a0940b2", |cb| orr(cb, X10, X11, A64Opnd::new_uimm(7))); + let cb = compile(|cb| orr(cb, X10, X11, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, #7"); + assert_snapshot!(cb.string(), @"6a0940b2"); } #[test] fn test_orr_32b_immediate() { - check_bytes("6a010032", |cb| orr(cb, W10, W11, A64Opnd::new_uimm(1))); + let cb = compile(|cb| orr(cb, W10, W11, A64Opnd::new_uimm(1))); + assert_snapshot!(cb.disasm(), @" 0x0: orr w10, w11, #1"); + assert_snapshot!(cb.string(), @"6a010032"); } #[test] fn test_ret_none() { - check_bytes("c0035fd6", |cb| ret(cb, A64Opnd::None)); + let cb = compile(|cb| ret(cb, A64Opnd::None)); + assert_snapshot!(cb.disasm(), @" 0x0: ret"); + assert_snapshot!(cb.string(), @"c0035fd6"); } #[test] fn test_ret_register() { - check_bytes("80025fd6", |cb| ret(cb, X20)); + let cb = compile(|cb| ret(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: ret x20"); + assert_snapshot!(cb.string(), @"80025fd6"); } #[test] fn test_stlxr() { - check_bytes("8bfd0ac8", |cb| stlxr(cb, W10, X11, X12)); + let cb = compile(|cb| stlxr(cb, W10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: stlxr w10, x11, [x12]"); + assert_snapshot!(cb.string(), @"8bfd0ac8"); } #[test] fn test_stp() { - check_bytes("8a2d0da9", |cb| stp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]"); + assert_snapshot!(cb.string(), @"8a2d0da9"); } #[test] fn test_stp_pre() { - check_bytes("8a2d8da9", |cb| stp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]!"); + assert_snapshot!(cb.string(), @"8a2d8da9"); } #[test] fn test_stp_post() { - check_bytes("8a2d8da8", |cb| stp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12], #0xd0"); + assert_snapshot!(cb.string(), @"8a2d8da8"); } #[test] fn test_str_post() { - check_bytes("6a051ff8", |cb| str_post(cb, X10, A64Opnd::new_mem(64, X11, -16))); + let cb = compile(|cb| str_post(cb, X10, A64Opnd::new_mem(64, X11, -16))); + assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11], #0xfffffffffffffff0"); + assert_snapshot!(cb.string(), @"6a051ff8"); } #[test] fn test_str_pre() { - check_bytes("6a0d1ff8", |cb| str_pre(cb, X10, A64Opnd::new_mem(64, X11, -16))); + let cb = compile(|cb| str_pre(cb, X10, A64Opnd::new_mem(64, X11, -16))); + assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11, #-0x10]!"); + assert_snapshot!(cb.string(), @"6a0d1ff8"); } #[test] fn test_strh() { - check_bytes("6a190079", |cb| strh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]"); + assert_snapshot!(cb.string(), @"6a190079"); } #[test] fn test_strh_pre() { - check_bytes("6acd0078", |cb| strh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]!"); + assert_snapshot!(cb.string(), @"6acd0078"); } #[test] fn test_strh_post() { - check_bytes("6ac50078", |cb| strh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11], #0xc"); + assert_snapshot!(cb.string(), @"6ac50078"); } #[test] fn test_stur_64_bits() { - check_bytes("6a0108f8", |cb| stur(cb, X10, A64Opnd::new_mem(64, X11, 128))); + let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(64, X11, 128))); + assert_snapshot!(cb.disasm(), @" 0x0: stur x10, [x11, #0x80]"); + assert_snapshot!(cb.string(), @"6a0108f8"); } #[test] fn test_stur_32_bits() { - check_bytes("6a0108b8", |cb| stur(cb, X10, A64Opnd::new_mem(32, X11, 128))); + let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(32, X11, 128))); + assert_snapshot!(cb.disasm(), @" 0x0: stur w10, [x11, #0x80]"); + assert_snapshot!(cb.string(), @"6a0108b8"); } #[test] fn test_sub_reg() { - check_bytes("200002cb", |cb| sub(cb, X0, X1, X2)); + let cb = compile(|cb| sub(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002cb"); } #[test] fn test_sub_uimm() { - check_bytes("201c00d1", |cb| sub(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_sub_imm_positive() { - check_bytes("201c00d1", |cb| sub(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_sub_imm_negative() { - check_bytes("201c0091", |cb| sub(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_subs_reg() { - check_bytes("200002eb", |cb| subs(cb, X0, X1, X2)); + let cb = compile(|cb| subs(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002eb"); } #[test] fn test_subs_imm_positive() { - check_bytes("201c00f1", |cb| subs(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_subs_imm_negative() { - check_bytes("201c00b1", |cb| subs(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_subs_uimm() { - check_bytes("201c00f1", |cb| subs(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_sxtw() { - check_bytes("6a7d4093", |cb| sxtw(cb, X10, W11)); + let cb = compile(|cb| sxtw(cb, X10, W11)); + assert_snapshot!(cb.disasm(), @" 0x0: sxtw x10, w11"); + assert_snapshot!(cb.string(), @"6a7d4093"); } #[test] fn test_tbnz() { - check_bytes("4a005037", |cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + let cb = compile(|cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + assert_snapshot!(cb.disasm(), @" 0x0: tbnz w10, #0xa, #8"); + assert_snapshot!(cb.string(), @"4a005037"); } #[test] fn test_tbz() { - check_bytes("4a005036", |cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + let cb = compile(|cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + assert_snapshot!(cb.disasm(), @" 0x0: tbz w10, #0xa, #8"); + assert_snapshot!(cb.string(), @"4a005036"); } #[test] fn test_tst_register() { - check_bytes("1f0001ea", |cb| tst(cb, X0, X1)); + let cb = compile(|cb| tst(cb, X0, X1)); + assert_snapshot!(cb.disasm(), @" 0x0: tst x0, x1"); + assert_snapshot!(cb.string(), @"1f0001ea"); } #[test] fn test_tst_immediate() { - check_bytes("3f0840f2", |cb| tst(cb, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| tst(cb, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: tst x1, #7"); + assert_snapshot!(cb.string(), @"3f0840f2"); } #[test] fn test_tst_32b_immediate() { - check_bytes("1f3c0072", |cb| tst(cb, W0, A64Opnd::new_uimm(0xffff))); + let cb = compile(|cb| tst(cb, W0, A64Opnd::new_uimm(0xffff))); + assert_snapshot!(cb.disasm(), @" 0x0: tst w0, #0xffff"); + assert_snapshot!(cb.string(), @"1f3c0072"); } #[test] @@ -1760,10 +1956,11 @@ mod tests { add_extended(&mut cb, X30, X30, X30); add_extended(&mut cb, X31, X31, X31); - assert_disasm!(cb, "6a61298bde633e8bff633f8b", " + assert_snapshot!(cb.disasm(), @" 0x0: add x10, x11, x9, uxtx 0x4: add x30, x30, x30, uxtx 0x8: add sp, sp, xzr "); + assert_snapshot!(cb.string(), @"6a61298bde633e8bff633f8b"); } } diff --git a/zjit/src/asm/mod.rs b/zjit/src/asm/mod.rs index e07ac0a48c3d89..d866515c82373a 100644 --- a/zjit/src/asm/mod.rs +++ b/zjit/src/asm/mod.rs @@ -281,6 +281,25 @@ impl CodeBlock { pub fn mark_all_executable(&mut self) { self.mem_block.borrow_mut().mark_all_executable(); } + + /// Return the disasm of generated code for testing + #[cfg(test)] + pub fn disasm(&self) -> String { + #[cfg(feature = "disasm")] + { + let start_addr = self.get_ptr(0).raw_addr(self); + let end_addr = self.get_write_ptr().raw_addr(self); + crate::disasm::disasm_addr_range(self, start_addr, end_addr) + } + #[cfg(not(feature = "disasm"))] + unreachable!("zjit-test should enable disasm feature") + } + + /// Return the hex dump of generated code for testing + #[cfg(test)] + pub fn string(&self) -> String { + format!("{:x}", self) + } } /// Produce hex string output from the bytes in a code block diff --git a/zjit/src/asm/x86_64/tests.rs b/zjit/src/asm/x86_64/tests.rs index 0268846e10c883..aa8d31b215b6c7 100644 --- a/zjit/src/asm/x86_64/tests.rs +++ b/zjit/src/asm/x86_64/tests.rs @@ -1,5 +1,7 @@ #![cfg(test)] +use insta::assert_snapshot; + use crate::asm::x86_64::*; /// Check that the bytes for an instruction sequence match a hex string @@ -9,364 +11,745 @@ fn check_bytes(bytes: &str, run: R) where R: FnOnce(&mut super::CodeBlock) { assert_eq!(format!("{:x}", cb), bytes); } +fn compile(run: R) -> CodeBlock where R: FnOnce(&mut super::CodeBlock) { + let mut cb = super::CodeBlock::new_dummy(); + run(&mut cb); + cb +} + #[test] fn test_add() { - check_bytes("80c103", |cb| add(cb, CL, imm_opnd(3))); - check_bytes("00d9", |cb| add(cb, CL, BL)); - check_bytes("4000e1", |cb| add(cb, CL, SPL)); - check_bytes("6601d9", |cb| add(cb, CX, BX)); - check_bytes("4801d8", |cb| add(cb, RAX, RBX)); - check_bytes("01d1", |cb| add(cb, ECX, EDX)); - check_bytes("4c01f2", |cb| add(cb, RDX, R14)); - check_bytes("480110", |cb| add(cb, mem_opnd(64, RAX, 0), RDX)); - check_bytes("480310", |cb| add(cb, RDX, mem_opnd(64, RAX, 0))); - check_bytes("48035008", |cb| add(cb, RDX, mem_opnd(64, RAX, 8))); - check_bytes("480390ff000000", |cb| add(cb, RDX, mem_opnd(64, RAX, 255))); - check_bytes("4881407fff000000", |cb| add(cb, mem_opnd(64, RAX, 127), imm_opnd(255))); - check_bytes("0110", |cb| add(cb, mem_opnd(32, RAX, 0), EDX)); - check_bytes("4883c408", |cb| add(cb, RSP, imm_opnd(8))); - check_bytes("83c108", |cb| add(cb, ECX, imm_opnd(8))); - check_bytes("81c1ff000000", |cb| add(cb, ECX, imm_opnd(255))); + let cb01 = compile(|cb| add(cb, CL, imm_opnd(3))); + let cb02 = compile(|cb| add(cb, CL, BL)); + let cb03 = compile(|cb| add(cb, CL, SPL)); + let cb04 = compile(|cb| add(cb, CX, BX)); + let cb05 = compile(|cb| add(cb, RAX, RBX)); + let cb06 = compile(|cb| add(cb, ECX, EDX)); + let cb07 = compile(|cb| add(cb, RDX, R14)); + let cb08 = compile(|cb| add(cb, mem_opnd(64, RAX, 0), RDX)); + let cb09 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 0))); + let cb10 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 8))); + let cb11 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 255))); + let cb12 = compile(|cb| add(cb, mem_opnd(64, RAX, 127), imm_opnd(255))); + let cb13 = compile(|cb| add(cb, mem_opnd(32, RAX, 0), EDX)); + let cb14 = compile(|cb| add(cb, RSP, imm_opnd(8))); + let cb15 = compile(|cb| add(cb, ECX, imm_opnd(8))); + let cb16 = compile(|cb| add(cb, ECX, imm_opnd(255))); + + assert_snapshot!(cb01.disasm(), @" 0x0: add cl, 3"); + assert_snapshot!(cb02.disasm(), @" 0x0: add cl, bl"); + assert_snapshot!(cb03.disasm(), @" 0x0: add cl, spl"); + assert_snapshot!(cb04.disasm(), @" 0x0: add cx, bx"); + assert_snapshot!(cb05.disasm(), @" 0x0: add rax, rbx"); + assert_snapshot!(cb06.disasm(), @" 0x0: add ecx, edx"); + assert_snapshot!(cb07.disasm(), @" 0x0: add rdx, r14"); + assert_snapshot!(cb08.disasm(), @" 0x0: add qword ptr [rax], rdx"); + assert_snapshot!(cb09.disasm(), @" 0x0: add rdx, qword ptr [rax]"); + assert_snapshot!(cb10.disasm(), @" 0x0: add rdx, qword ptr [rax + 8]"); + assert_snapshot!(cb11.disasm(), @" 0x0: add rdx, qword ptr [rax + 0xff]"); + assert_snapshot!(cb12.disasm(), @" 0x0: add qword ptr [rax + 0x7f], 0xff"); + assert_snapshot!(cb13.disasm(), @" 0x0: add dword ptr [rax], edx"); + assert_snapshot!(cb14.disasm(), @" 0x0: add rsp, 8"); + assert_snapshot!(cb15.disasm(), @" 0x0: add ecx, 8"); + assert_snapshot!(cb16.disasm(), @" 0x0: add ecx, 0xff"); + + assert_snapshot!(cb01.string(), @"80c103"); + assert_snapshot!(cb02.string(), @"00d9"); + assert_snapshot!(cb03.string(), @"4000e1"); + assert_snapshot!(cb04.string(), @"6601d9"); + assert_snapshot!(cb05.string(), @"4801d8"); + assert_snapshot!(cb06.string(), @"01d1"); + assert_snapshot!(cb07.string(), @"4c01f2"); + assert_snapshot!(cb08.string(), @"480110"); + assert_snapshot!(cb09.string(), @"480310"); + assert_snapshot!(cb10.string(), @"48035008"); + assert_snapshot!(cb11.string(), @"480390ff000000"); + assert_snapshot!(cb12.string(), @"4881407fff000000"); + assert_snapshot!(cb13.string(), @"0110"); + assert_snapshot!(cb14.string(), @"4883c408"); + assert_snapshot!(cb15.string(), @"83c108"); + assert_snapshot!(cb16.string(), @"81c1ff000000"); } #[test] fn test_add_unsigned() { // ADD r/m8, imm8 - check_bytes("4180c001", |cb| add(cb, R8B, uimm_opnd(1))); - check_bytes("4180c07f", |cb| add(cb, R8B, imm_opnd(i8::MAX.into()))); - + let cb1 = compile(|cb| add(cb, R8B, uimm_opnd(1))); + let cb2 = compile(|cb| add(cb, R8B, imm_opnd(i8::MAX.into()))); // ADD r/m16, imm16 - check_bytes("664183c001", |cb| add(cb, R8W, uimm_opnd(1))); - check_bytes("664181c0ff7f", |cb| add(cb, R8W, uimm_opnd(i16::MAX.try_into().unwrap()))); - + let cb3 = compile(|cb| add(cb, R8W, uimm_opnd(1))); + let cb4 = compile(|cb| add(cb, R8W, uimm_opnd(i16::MAX.try_into().unwrap()))); // ADD r/m32, imm32 - check_bytes("4183c001", |cb| add(cb, R8D, uimm_opnd(1))); - check_bytes("4181c0ffffff7f", |cb| add(cb, R8D, uimm_opnd(i32::MAX.try_into().unwrap()))); - + let cb5 = compile(|cb| add(cb, R8D, uimm_opnd(1))); + let cb6 = compile(|cb| add(cb, R8D, uimm_opnd(i32::MAX.try_into().unwrap()))); // ADD r/m64, imm32 - check_bytes("4983c001", |cb| add(cb, R8, uimm_opnd(1))); - check_bytes("4981c0ffffff7f", |cb| add(cb, R8, uimm_opnd(i32::MAX.try_into().unwrap()))); + let cb7 = compile(|cb| add(cb, R8, uimm_opnd(1))); + let cb8 = compile(|cb| add(cb, R8, uimm_opnd(i32::MAX.try_into().unwrap()))); + + assert_snapshot!(cb1.disasm(), @" 0x0: add r8b, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: add r8b, 0x7f"); + assert_snapshot!(cb3.disasm(), @" 0x0: add r8w, 1"); + assert_snapshot!(cb4.disasm(), @" 0x0: add r8w, 0x7fff"); + assert_snapshot!(cb5.disasm(), @" 0x0: add r8d, 1"); + assert_snapshot!(cb6.disasm(), @" 0x0: add r8d, 0x7fffffff"); + assert_snapshot!(cb7.disasm(), @" 0x0: add r8, 1"); + assert_snapshot!(cb8.disasm(), @" 0x0: add r8, 0x7fffffff"); + + assert_snapshot!(cb1.string(), @"4180c001"); + assert_snapshot!(cb2.string(), @"4180c07f"); + assert_snapshot!(cb3.string(), @"664183c001"); + assert_snapshot!(cb4.string(), @"664181c0ff7f"); + assert_snapshot!(cb5.string(), @"4183c001"); + assert_snapshot!(cb6.string(), @"4181c0ffffff7f"); + assert_snapshot!(cb7.string(), @"4983c001"); + assert_snapshot!(cb8.string(), @"4981c0ffffff7f"); } #[test] fn test_and() { - check_bytes("4421e5", |cb| and(cb, EBP, R12D)); - check_bytes("48832008", |cb| and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08))); + let cb1 = compile(|cb| and(cb, EBP, R12D)); + let cb2 = compile(|cb| and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08))); + + assert_snapshot!(cb1.disasm(), @" 0x0: and ebp, r12d"); + assert_snapshot!(cb2.disasm(), @" 0x0: and qword ptr [rax], 8"); + + assert_snapshot!(cb1.string(), @"4421e5"); + assert_snapshot!(cb2.string(), @"48832008"); } #[test] fn test_call_label() { - check_bytes("e8fbffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("fn".to_owned()); call_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: call 0"); + assert_snapshot!(cb.string(), @"e8fbffffff"); } #[test] fn test_call_ptr() { // calling a lower address - check_bytes("e8fbffffff", |cb| { + let cb = compile(|cb| { let ptr = cb.get_write_ptr(); call_ptr(cb, RAX, ptr.raw_ptr(cb)); }); + assert_snapshot!(cb.disasm(), @" 0x0: call 0"); + assert_snapshot!(cb.string(), @"e8fbffffff"); } #[test] fn test_call_reg() { - check_bytes("ffd0", |cb| call(cb, RAX)); + let cb = compile(|cb| call(cb, RAX)); + assert_snapshot!(cb.disasm(), @" 0x0: call rax"); + assert_snapshot!(cb.string(), @"ffd0"); } #[test] fn test_call_mem() { - check_bytes("ff542408", |cb| call(cb, mem_opnd(64, RSP, 8))); + let cb = compile(|cb| call(cb, mem_opnd(64, RSP, 8))); + assert_snapshot!(cb.disasm(), @" 0x0: call qword ptr [rsp + 8]"); + assert_snapshot!(cb.string(), @"ff542408"); } #[test] fn test_cmovcc() { - check_bytes("0f4ff7", |cb| cmovg(cb, ESI, EDI)); - check_bytes("0f4f750c", |cb| cmovg(cb, ESI, mem_opnd(32, RBP, 12))); - check_bytes("0f4cc1", |cb| cmovl(cb, EAX, ECX)); - check_bytes("480f4cdd", |cb| cmovl(cb, RBX, RBP)); - check_bytes("0f4e742404", |cb| cmovle(cb, ESI, mem_opnd(32, RSP, 4))); + let cb1 = compile(|cb| cmovg(cb, ESI, EDI)); + let cb2 = compile(|cb| cmovg(cb, ESI, mem_opnd(32, RBP, 12))); + let cb3 = compile(|cb| cmovl(cb, EAX, ECX)); + let cb4 = compile(|cb| cmovl(cb, RBX, RBP)); + let cb5 = compile(|cb| cmovle(cb, ESI, mem_opnd(32, RSP, 4))); + + assert_snapshot!(cb1.disasm(), @" 0x0: cmovg esi, edi"); + assert_snapshot!(cb2.disasm(), @" 0x0: cmovg esi, dword ptr [rbp + 0xc]"); + assert_snapshot!(cb3.disasm(), @" 0x0: cmovl eax, ecx"); + assert_snapshot!(cb4.disasm(), @" 0x0: cmovl rbx, rbp"); + assert_snapshot!(cb5.disasm(), @" 0x0: cmovle esi, dword ptr [rsp + 4]"); + + assert_snapshot!(cb1.string(), @"0f4ff7"); + assert_snapshot!(cb2.string(), @"0f4f750c"); + assert_snapshot!(cb3.string(), @"0f4cc1"); + assert_snapshot!(cb4.string(), @"480f4cdd"); + assert_snapshot!(cb5.string(), @"0f4e742404"); } #[test] fn test_cmp() { - check_bytes("38d1", |cb| cmp(cb, CL, DL)); - check_bytes("39f9", |cb| cmp(cb, ECX, EDI)); - check_bytes("493b1424", |cb| cmp(cb, RDX, mem_opnd(64, R12, 0))); - check_bytes("4883f802", |cb| cmp(cb, RAX, imm_opnd(2))); - check_bytes("81f900000080", |cb| cmp(cb, ECX, uimm_opnd(0x8000_0000))); + let cb1 = compile(|cb| cmp(cb, CL, DL)); + let cb2 = compile(|cb| cmp(cb, ECX, EDI)); + let cb3 = compile(|cb| cmp(cb, RDX, mem_opnd(64, R12, 0))); + let cb4 = compile(|cb| cmp(cb, RAX, imm_opnd(2))); + let cb5 = compile(|cb| cmp(cb, ECX, uimm_opnd(0x8000_0000))); + + assert_snapshot!(cb1.disasm(), @" 0x0: cmp cl, dl"); + assert_snapshot!(cb2.disasm(), @" 0x0: cmp ecx, edi"); + assert_snapshot!(cb3.disasm(), @" 0x0: cmp rdx, qword ptr [r12]"); + assert_snapshot!(cb4.disasm(), @" 0x0: cmp rax, 2"); + assert_snapshot!(cb5.disasm(), @" 0x0: cmp ecx, 0x80000000"); + + assert_snapshot!(cb1.string(), @"38d1"); + assert_snapshot!(cb2.string(), @"39f9"); + assert_snapshot!(cb3.string(), @"493b1424"); + assert_snapshot!(cb4.string(), @"4883f802"); + assert_snapshot!(cb5.string(), @"81f900000080"); } #[test] fn test_cqo() { - check_bytes("4899", cqo); + let cb = compile(cqo); + assert_snapshot!(cb.disasm(), @" 0x0: cqo"); + assert_snapshot!(cb.string(), @"4899"); } #[test] fn test_imul() { - check_bytes("480fafc3", |cb| imul(cb, RAX, RBX)); - check_bytes("480faf10", |cb| imul(cb, RDX, mem_opnd(64, RAX, 0))); - + let cb1 = compile(|cb| imul(cb, RAX, RBX)); + let cb2 = compile(|cb| imul(cb, RDX, mem_opnd(64, RAX, 0))); // Operands flipped for encoding since multiplication is commutative - check_bytes("480faf10", |cb| imul(cb, mem_opnd(64, RAX, 0), RDX)); + let cb3 = compile(|cb| imul(cb, mem_opnd(64, RAX, 0), RDX)); + + assert_snapshot!(cb1.disasm(), @" 0x0: imul rax, rbx"); + assert_snapshot!(cb2.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); + assert_snapshot!(cb3.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); + + assert_snapshot!(cb1.string(), @"480fafc3"); + assert_snapshot!(cb2.string(), @"480faf10"); + assert_snapshot!(cb3.string(), @"480faf10"); } #[test] fn test_jge_label() { - check_bytes("0f8dfaffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); jge_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: jge 0"); + assert_snapshot!(cb.string(), @"0f8dfaffffff"); } #[test] fn test_jmp_label() { // Forward jump - check_bytes("e900000000", |cb| { + let cb1 = compile(|cb| { let label_idx = cb.new_label("next".to_owned()); jmp_label(cb, label_idx); cb.write_label(label_idx); cb.link_labels(); }); - // Backwards jump - check_bytes("e9fbffffff", |cb| { + let cb2 = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); cb.write_label(label_idx); jmp_label(cb, label_idx); cb.link_labels(); }); + + assert_snapshot!(cb1.disasm(), @" 0x0: jmp 5"); + assert_snapshot!(cb2.disasm(), @" 0x0: jmp 0"); + + assert_snapshot!(cb1.string(), @"e900000000"); + assert_snapshot!(cb2.string(), @"e9fbffffff"); } #[test] fn test_jmp_rm() { - check_bytes("41ffe4", |cb| jmp_rm(cb, R12)); + let cb = compile(|cb| jmp_rm(cb, R12)); + assert_snapshot!(cb.disasm(), @" 0x0: jmp r12"); + assert_snapshot!(cb.string(), @"41ffe4"); } #[test] fn test_jo_label() { - check_bytes("0f80faffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); jo_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: jo 0"); + assert_snapshot!(cb.string(), @"0f80faffffff"); } #[test] fn test_lea() { - check_bytes("488d5108", |cb| lea(cb, RDX, mem_opnd(64, RCX, 8))); - check_bytes("488d0500000000", |cb| lea(cb, RAX, mem_opnd(8, RIP, 0))); - check_bytes("488d0505000000", |cb| lea(cb, RAX, mem_opnd(8, RIP, 5))); - check_bytes("488d3d05000000", |cb| lea(cb, RDI, mem_opnd(8, RIP, 5))); + let cb1 = compile(|cb| lea(cb, RDX, mem_opnd(64, RCX, 8))); + let cb2 = compile(|cb| lea(cb, RAX, mem_opnd(8, RIP, 0))); + let cb3 = compile(|cb| lea(cb, RAX, mem_opnd(8, RIP, 5))); + let cb4 = compile(|cb| lea(cb, RDI, mem_opnd(8, RIP, 5))); + + assert_snapshot!(cb1.disasm(), @" 0x0: lea rdx, [rcx + 8]"); + assert_snapshot!(cb2.disasm(), @" 0x0: lea rax, [rip]"); + assert_snapshot!(cb3.disasm(), @" 0x0: lea rax, [rip + 5]"); + assert_snapshot!(cb4.disasm(), @" 0x0: lea rdi, [rip + 5]"); + + assert_snapshot!(cb1.string(), @"488d5108"); + assert_snapshot!(cb2.string(), @"488d0500000000"); + assert_snapshot!(cb3.string(), @"488d0505000000"); + assert_snapshot!(cb4.string(), @"488d3d05000000"); } #[test] fn test_mov() { - check_bytes("b807000000", |cb| mov(cb, EAX, imm_opnd(7))); - check_bytes("b8fdffffff", |cb| mov(cb, EAX, imm_opnd(-3))); - check_bytes("41bf03000000", |cb| mov(cb, R15, imm_opnd(3))); - check_bytes("89d8", |cb| mov(cb, EAX, EBX)); - check_bytes("89c8", |cb| mov(cb, EAX, ECX)); - check_bytes("8b9380000000", |cb| mov(cb, EDX, mem_opnd(32, RBX, 128))); - check_bytes("488b442404", |cb| mov(cb, RAX, mem_opnd(64, RSP, 4))); - + let cb01 = compile(|cb| mov(cb, EAX, imm_opnd(7))); + let cb02 = compile(|cb| mov(cb, EAX, imm_opnd(-3))); + let cb03 = compile(|cb| mov(cb, R15, imm_opnd(3))); + let cb04 = compile(|cb| mov(cb, EAX, EBX)); + let cb05 = compile(|cb| mov(cb, EAX, ECX)); + let cb06 = compile(|cb| mov(cb, EDX, mem_opnd(32, RBX, 128))); + let cb07 = compile(|cb| mov(cb, RAX, mem_opnd(64, RSP, 4))); // Test `mov rax, 3` => `mov eax, 3` optimization - check_bytes("41b834000000", |cb| mov(cb, R8, imm_opnd(0x34))); - check_bytes("49b80000008000000000", |cb| mov(cb, R8, imm_opnd(0x80000000))); - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, imm_opnd(-1))); - - check_bytes("b834000000", |cb| mov(cb, RAX, imm_opnd(0x34))); - check_bytes("48b8020000000000c0ff", |cb| mov(cb, RAX, imm_opnd(-18014398509481982))); - check_bytes("48b80000008000000000", |cb| mov(cb, RAX, imm_opnd(0x80000000))); - check_bytes("48b8ccffffffffffffff", |cb| mov(cb, RAX, imm_opnd(-52))); // yasm thinks this could use a dword immediate instead of qword - check_bytes("48b8ffffffffffffffff", |cb| mov(cb, RAX, imm_opnd(-1))); // yasm thinks this could use a dword immediate instead of qword - check_bytes("4488c9", |cb| mov(cb, CL, R9B)); - check_bytes("4889c3", |cb| mov(cb, RBX, RAX)); - check_bytes("4889df", |cb| mov(cb, RDI, RBX)); - check_bytes("40b60b", |cb| mov(cb, SIL, imm_opnd(11))); - - check_bytes("c60424fd", |cb| mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3))); - check_bytes("48c7470801000000", |cb| mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1))); - //check_bytes("67c7400411000000", |cb| mov(cb, mem_opnd(32, EAX, 4), imm_opnd(0x34))); // We don't distinguish between EAX and RAX here - that's probably fine? - check_bytes("c7400411000000", |cb| mov(cb, mem_opnd(32, RAX, 4), imm_opnd(17))); - check_bytes("c7400401000080", |cb| mov(cb, mem_opnd(32, RAX, 4), uimm_opnd(0x80000001))); - check_bytes("41895814", |cb| mov(cb, mem_opnd(32, R8, 20), EBX)); - check_bytes("4d8913", |cb| mov(cb, mem_opnd(64, R11, 0), R10)); - check_bytes("48c742f8f4ffffff", |cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12))); + let cb08 = compile(|cb| mov(cb, R8, imm_opnd(0x34))); + let cb09 = compile(|cb| mov(cb, R8, imm_opnd(0x80000000))); + let cb10 = compile(|cb| mov(cb, R8, imm_opnd(-1))); + let cb11 = compile(|cb| mov(cb, RAX, imm_opnd(0x34))); + let cb12 = compile(|cb| mov(cb, RAX, imm_opnd(-18014398509481982))); + let cb13 = compile(|cb| mov(cb, RAX, imm_opnd(0x80000000))); + let cb14 = compile(|cb| mov(cb, RAX, imm_opnd(-52))); // yasm thinks this could use a dword immediate instead of qword + let cb15 = compile(|cb| mov(cb, RAX, imm_opnd(-1))); // yasm thinks this could use a dword immediate instead of qword + let cb16 = compile(|cb| mov(cb, CL, R9B)); + let cb17 = compile(|cb| mov(cb, RBX, RAX)); + let cb18 = compile(|cb| mov(cb, RDI, RBX)); + let cb19 = compile(|cb| mov(cb, SIL, imm_opnd(11))); + let cb20 = compile(|cb| mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3))); + let cb21 = compile(|cb| mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1))); + //let cb = compile(|cb| mov(cb, mem_opnd(32, EAX, 4), imm_opnd(0x34))); // We don't distinguish between EAX and RAX here - that's probably fine? + let cb22 = compile(|cb| mov(cb, mem_opnd(32, RAX, 4), imm_opnd(17))); + let cb23 = compile(|cb| mov(cb, mem_opnd(32, RAX, 4), uimm_opnd(0x80000001))); + let cb24 = compile(|cb| mov(cb, mem_opnd(32, R8, 20), EBX)); + let cb25 = compile(|cb| mov(cb, mem_opnd(64, R11, 0), R10)); + let cb26 = compile(|cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12))); + + assert_snapshot!(cb01.disasm(), @" 0x0: mov eax, 7"); + assert_snapshot!(cb02.disasm(), @" 0x0: mov eax, 0xfffffffd"); + assert_snapshot!(cb03.disasm(), @" 0x0: mov r15d, 3"); + assert_snapshot!(cb04.disasm(), @" 0x0: mov eax, ebx"); + assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, ecx"); + assert_snapshot!(cb06.disasm(), @" 0x0: mov edx, dword ptr [rbx + 0x80]"); + assert_snapshot!(cb07.disasm(), @" 0x0: mov rax, qword ptr [rsp + 4]"); + assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0x34"); + assert_snapshot!(cb09.disasm(), @" 0x0: movabs r8, 0x80000000"); + assert_snapshot!(cb10.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + assert_snapshot!(cb11.disasm(), @" 0x0: mov eax, 0x34"); + assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffc0000000000002"); + assert_snapshot!(cb13.disasm(), @" 0x0: movabs rax, 0x80000000"); + assert_snapshot!(cb14.disasm(), @" 0x0: movabs rax, 0xffffffffffffffcc"); + assert_snapshot!(cb15.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); + assert_snapshot!(cb16.disasm(), @" 0x0: mov cl, r9b"); + assert_snapshot!(cb17.disasm(), @" 0x0: mov rbx, rax"); + assert_snapshot!(cb18.disasm(), @" 0x0: mov rdi, rbx"); + assert_snapshot!(cb19.disasm(), @" 0x0: mov sil, 0xb"); + assert_snapshot!(cb20.disasm(), @" 0x0: mov byte ptr [rsp], 0xfd"); + assert_snapshot!(cb21.disasm(), @" 0x0: mov qword ptr [rdi + 8], 1"); + assert_snapshot!(cb22.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x11"); + assert_snapshot!(cb23.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x80000001"); + assert_snapshot!(cb24.disasm(), @" 0x0: mov dword ptr [r8 + 0x14], ebx"); + assert_snapshot!(cb25.disasm(), @" 0x0: mov qword ptr [r11], r10"); + assert_snapshot!(cb26.disasm(), @" 0x0: mov qword ptr [rdx - 8], 0xfffffffffffffff4"); + + assert_snapshot!(cb01.string(), @"b807000000"); + assert_snapshot!(cb02.string(), @"b8fdffffff"); + assert_snapshot!(cb03.string(), @"41bf03000000"); + assert_snapshot!(cb04.string(), @"89d8"); + assert_snapshot!(cb05.string(), @"89c8"); + assert_snapshot!(cb06.string(), @"8b9380000000"); + assert_snapshot!(cb07.string(), @"488b442404"); + assert_snapshot!(cb08.string(), @"41b834000000"); + assert_snapshot!(cb09.string(), @"49b80000008000000000"); + assert_snapshot!(cb10.string(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb11.string(), @"b834000000"); + assert_snapshot!(cb12.string(), @"48b8020000000000c0ff"); + assert_snapshot!(cb13.string(), @"48b80000008000000000"); + assert_snapshot!(cb14.string(), @"48b8ccffffffffffffff"); + assert_snapshot!(cb15.string(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb16.string(), @"4488c9"); + assert_snapshot!(cb17.string(), @"4889c3"); + assert_snapshot!(cb18.string(), @"4889df"); + assert_snapshot!(cb19.string(), @"40b60b"); + assert_snapshot!(cb20.string(), @"c60424fd"); + assert_snapshot!(cb21.string(), @"48c7470801000000"); + assert_snapshot!(cb22.string(), @"c7400411000000"); + assert_snapshot!(cb23.string(), @"c7400401000080"); + assert_snapshot!(cb24.string(), @"41895814"); + assert_snapshot!(cb25.string(), @"4d8913"); + assert_snapshot!(cb26.string(), @"48c742f8f4ffffff"); } #[test] fn test_movabs() { - check_bytes("49b83400000000000000", |cb| movabs(cb, R8, 0x34)); - check_bytes("49b80000008000000000", |cb| movabs(cb, R8, 0x80000000)); + let cb1 = compile(|cb| movabs(cb, R8, 0x34)); + let cb2 = compile(|cb| movabs(cb, R8, 0x80000000)); + + assert_snapshot!(cb1.disasm(), @" 0x0: movabs r8, 0x34"); + assert_snapshot!(cb2.disasm(), @" 0x0: movabs r8, 0x80000000"); + + assert_snapshot!(cb1.string(), @"49b83400000000000000"); + assert_snapshot!(cb2.string(), @"49b80000008000000000"); } #[test] fn test_mov_unsigned() { // MOV AL, imm8 - check_bytes("b001", |cb| mov(cb, AL, uimm_opnd(1))); - check_bytes("b0ff", |cb| mov(cb, AL, uimm_opnd(u8::MAX.into()))); - + let cb01 = compile(|cb| mov(cb, AL, uimm_opnd(1))); + let cb02 = compile(|cb| mov(cb, AL, uimm_opnd(u8::MAX.into()))); // MOV AX, imm16 - check_bytes("66b80100", |cb| mov(cb, AX, uimm_opnd(1))); - check_bytes("66b8ffff", |cb| mov(cb, AX, uimm_opnd(u16::MAX.into()))); - + let cb03 = compile(|cb| mov(cb, AX, uimm_opnd(1))); + let cb04 = compile(|cb| mov(cb, AX, uimm_opnd(u16::MAX.into()))); // MOV EAX, imm32 - check_bytes("b801000000", |cb| mov(cb, EAX, uimm_opnd(1))); - check_bytes("b8ffffffff", |cb| mov(cb, EAX, uimm_opnd(u32::MAX.into()))); - check_bytes("41b800000000", |cb| mov(cb, R8, uimm_opnd(0))); - check_bytes("41b8ffffffff", |cb| mov(cb, R8, uimm_opnd(0xFF_FF_FF_FF))); - + let cb05 = compile(|cb| mov(cb, EAX, uimm_opnd(1))); + let cb06 = compile(|cb| mov(cb, EAX, uimm_opnd(u32::MAX.into()))); + let cb07 = compile(|cb| mov(cb, R8, uimm_opnd(0))); + let cb08 = compile(|cb| mov(cb, R8, uimm_opnd(0xFF_FF_FF_FF))); // MOV RAX, imm64, will move down into EAX since it fits into 32 bits - check_bytes("b801000000", |cb| mov(cb, RAX, uimm_opnd(1))); - check_bytes("b8ffffffff", |cb| mov(cb, RAX, uimm_opnd(u32::MAX.into()))); - + let cb09 = compile(|cb| mov(cb, RAX, uimm_opnd(1))); + let cb10 = compile(|cb| mov(cb, RAX, uimm_opnd(u32::MAX.into()))); // MOV RAX, imm64, will not move down into EAX since it does not fit into 32 bits - check_bytes("48b80000000001000000", |cb| mov(cb, RAX, uimm_opnd(u32::MAX as u64 + 1))); - check_bytes("48b8ffffffffffffffff", |cb| mov(cb, RAX, uimm_opnd(u64::MAX))); - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, uimm_opnd(u64::MAX))); - + let cb11 = compile(|cb| mov(cb, RAX, uimm_opnd(u32::MAX as u64 + 1))); + let cb12 = compile(|cb| mov(cb, RAX, uimm_opnd(u64::MAX))); + let cb13 = compile(|cb| mov(cb, R8, uimm_opnd(u64::MAX))); // MOV r8, imm8 - check_bytes("41b001", |cb| mov(cb, R8B, uimm_opnd(1))); - check_bytes("41b0ff", |cb| mov(cb, R8B, uimm_opnd(u8::MAX.into()))); - + let cb14 = compile(|cb| mov(cb, R8B, uimm_opnd(1))); + let cb15 = compile(|cb| mov(cb, R8B, uimm_opnd(u8::MAX.into()))); // MOV r16, imm16 - check_bytes("6641b80100", |cb| mov(cb, R8W, uimm_opnd(1))); - check_bytes("6641b8ffff", |cb| mov(cb, R8W, uimm_opnd(u16::MAX.into()))); - + let cb16 = compile(|cb| mov(cb, R8W, uimm_opnd(1))); + let cb17 = compile(|cb| mov(cb, R8W, uimm_opnd(u16::MAX.into()))); // MOV r32, imm32 - check_bytes("41b801000000", |cb| mov(cb, R8D, uimm_opnd(1))); - check_bytes("41b8ffffffff", |cb| mov(cb, R8D, uimm_opnd(u32::MAX.into()))); - + let cb18 = compile(|cb| mov(cb, R8D, uimm_opnd(1))); + let cb19 = compile(|cb| mov(cb, R8D, uimm_opnd(u32::MAX.into()))); // MOV r64, imm64, will move down into 32 bit since it fits into 32 bits - check_bytes("41b801000000", |cb| mov(cb, R8, uimm_opnd(1))); - + let cb20 = compile(|cb| mov(cb, R8, uimm_opnd(1))); // MOV r64, imm64, will not move down into 32 bit since it does not fit into 32 bits - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, uimm_opnd(u64::MAX))); + let cb21 = compile(|cb| mov(cb, R8, uimm_opnd(u64::MAX))); + + assert_snapshot!(cb01.disasm(), @" 0x0: mov al, 1"); + assert_snapshot!(cb02.disasm(), @" 0x0: mov al, 0xff"); + assert_snapshot!(cb03.disasm(), @" 0x0: mov ax, 1"); + assert_snapshot!(cb04.disasm(), @" 0x0: mov ax, 0xffff"); + assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, 1"); + assert_snapshot!(cb06.disasm(), @" 0x0: mov eax, 0xffffffff"); + assert_snapshot!(cb07.disasm(), @" 0x0: mov r8d, 0"); + assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0xffffffff"); + assert_snapshot!(cb09.disasm(), @" 0x0: mov eax, 1"); + assert_snapshot!(cb10.disasm(), @" 0x0: mov eax, 0xffffffff"); + assert_snapshot!(cb11.disasm(), @" 0x0: movabs rax, 0x100000000"); + assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); + assert_snapshot!(cb13.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + assert_snapshot!(cb14.disasm(), @" 0x0: mov r8b, 1"); + assert_snapshot!(cb15.disasm(), @" 0x0: mov r8b, 0xff"); + assert_snapshot!(cb16.disasm(), @" 0x0: mov r8w, 1"); + assert_snapshot!(cb17.disasm(), @" 0x0: mov r8w, 0xffff"); + assert_snapshot!(cb18.disasm(), @" 0x0: mov r8d, 1"); + assert_snapshot!(cb19.disasm(), @" 0x0: mov r8d, 0xffffffff"); + assert_snapshot!(cb20.disasm(), @" 0x0: mov r8d, 1"); + assert_snapshot!(cb21.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + + assert_snapshot!(cb01.string(), @"b001"); + assert_snapshot!(cb02.string(), @"b0ff"); + assert_snapshot!(cb03.string(), @"66b80100"); + assert_snapshot!(cb04.string(), @"66b8ffff"); + assert_snapshot!(cb05.string(), @"b801000000"); + assert_snapshot!(cb06.string(), @"b8ffffffff"); + assert_snapshot!(cb07.string(), @"41b800000000"); + assert_snapshot!(cb08.string(), @"41b8ffffffff"); + assert_snapshot!(cb09.string(), @"b801000000"); + assert_snapshot!(cb10.string(), @"b8ffffffff"); + assert_snapshot!(cb11.string(), @"48b80000000001000000"); + assert_snapshot!(cb12.string(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb13.string(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb14.string(), @"41b001"); + assert_snapshot!(cb15.string(), @"41b0ff"); + assert_snapshot!(cb16.string(), @"6641b80100"); + assert_snapshot!(cb17.string(), @"6641b8ffff"); + assert_snapshot!(cb18.string(), @"41b801000000"); + assert_snapshot!(cb19.string(), @"41b8ffffffff"); + assert_snapshot!(cb20.string(), @"41b801000000"); + assert_snapshot!(cb21.string(), @"49b8ffffffffffffffff"); } #[test] fn test_mov_iprel() { - check_bytes("8b0500000000", |cb| mov(cb, EAX, mem_opnd(32, RIP, 0))); - check_bytes("8b0505000000", |cb| mov(cb, EAX, mem_opnd(32, RIP, 5))); + let cb1 = compile(|cb| mov(cb, EAX, mem_opnd(32, RIP, 0))); + let cb2 = compile(|cb| mov(cb, EAX, mem_opnd(32, RIP, 5))); + let cb3 = compile(|cb| mov(cb, RAX, mem_opnd(64, RIP, 0))); + let cb4 = compile(|cb| mov(cb, RAX, mem_opnd(64, RIP, 5))); + let cb5 = compile(|cb| mov(cb, RDI, mem_opnd(64, RIP, 5))); + + assert_snapshot!(cb1.disasm(), @" 0x0: mov eax, dword ptr [rip]"); + assert_snapshot!(cb2.disasm(), @" 0x0: mov eax, dword ptr [rip + 5]"); + assert_snapshot!(cb3.disasm(), @" 0x0: mov rax, qword ptr [rip]"); + assert_snapshot!(cb4.disasm(), @" 0x0: mov rax, qword ptr [rip + 5]"); + assert_snapshot!(cb5.disasm(), @" 0x0: mov rdi, qword ptr [rip + 5]"); - check_bytes("488b0500000000", |cb| mov(cb, RAX, mem_opnd(64, RIP, 0))); - check_bytes("488b0505000000", |cb| mov(cb, RAX, mem_opnd(64, RIP, 5))); - check_bytes("488b3d05000000", |cb| mov(cb, RDI, mem_opnd(64, RIP, 5))); + assert_snapshot!(cb1.string(), @"8b0500000000"); + assert_snapshot!(cb2.string(), @"8b0505000000"); + assert_snapshot!(cb3.string(), @"488b0500000000"); + assert_snapshot!(cb4.string(), @"488b0505000000"); + assert_snapshot!(cb5.string(), @"488b3d05000000"); } #[test] fn test_movsx() { - check_bytes("660fbec0", |cb| movsx(cb, AX, AL)); - check_bytes("0fbed0", |cb| movsx(cb, EDX, AL)); - check_bytes("480fbec3", |cb| movsx(cb, RAX, BL)); - check_bytes("0fbfc8", |cb| movsx(cb, ECX, AX)); - check_bytes("4c0fbed9", |cb| movsx(cb, R11, CL)); - check_bytes("4c6354240c", |cb| movsx(cb, R10, mem_opnd(32, RSP, 12))); - check_bytes("480fbe0424", |cb| movsx(cb, RAX, mem_opnd(8, RSP, 0))); - check_bytes("490fbf5504", |cb| movsx(cb, RDX, mem_opnd(16, R13, 4))); + let cb1 = compile(|cb| movsx(cb, AX, AL)); + let cb2 = compile(|cb| movsx(cb, EDX, AL)); + let cb3 = compile(|cb| movsx(cb, RAX, BL)); + let cb4 = compile(|cb| movsx(cb, ECX, AX)); + let cb5 = compile(|cb| movsx(cb, R11, CL)); + let cb6 = compile(|cb| movsx(cb, R10, mem_opnd(32, RSP, 12))); + let cb7 = compile(|cb| movsx(cb, RAX, mem_opnd(8, RSP, 0))); + let cb8 = compile(|cb| movsx(cb, RDX, mem_opnd(16, R13, 4))); + + assert_snapshot!(cb1.disasm(), @" 0x0: movsx ax, al"); + assert_snapshot!(cb2.disasm(), @" 0x0: movsx edx, al"); + assert_snapshot!(cb3.disasm(), @" 0x0: movsx rax, bl"); + assert_snapshot!(cb4.disasm(), @" 0x0: movsx ecx, ax"); + assert_snapshot!(cb5.disasm(), @" 0x0: movsx r11, cl"); + assert_snapshot!(cb6.disasm(), @" 0x0: movsxd r10, dword ptr [rsp + 0xc]"); + assert_snapshot!(cb7.disasm(), @" 0x0: movsx rax, byte ptr [rsp]"); + assert_snapshot!(cb8.disasm(), @" 0x0: movsx rdx, word ptr [r13 + 4]"); + + assert_snapshot!(cb1.string(), @"660fbec0"); + assert_snapshot!(cb2.string(), @"0fbed0"); + assert_snapshot!(cb3.string(), @"480fbec3"); + assert_snapshot!(cb4.string(), @"0fbfc8"); + assert_snapshot!(cb5.string(), @"4c0fbed9"); + assert_snapshot!(cb6.string(), @"4c6354240c"); + assert_snapshot!(cb7.string(), @"480fbe0424"); + assert_snapshot!(cb8.string(), @"490fbf5504"); } #[test] fn test_nop() { - check_bytes("90", |cb| nop(cb, 1)); - check_bytes("6690", |cb| nop(cb, 2)); - check_bytes("0f1f00", |cb| nop(cb, 3)); - check_bytes("0f1f4000", |cb| nop(cb, 4)); - check_bytes("0f1f440000", |cb| nop(cb, 5)); - check_bytes("660f1f440000", |cb| nop(cb, 6)); - check_bytes("0f1f8000000000", |cb| nop(cb, 7)); - check_bytes("0f1f840000000000", |cb| nop(cb, 8)); - check_bytes("660f1f840000000000", |cb| nop(cb, 9)); - check_bytes("660f1f84000000000090", |cb| nop(cb, 10)); - check_bytes("660f1f8400000000006690", |cb| nop(cb, 11)); - check_bytes("660f1f8400000000000f1f00", |cb| nop(cb, 12)); + let cb01 = compile(|cb| nop(cb, 1)); + let cb02 = compile(|cb| nop(cb, 2)); + let cb03 = compile(|cb| nop(cb, 3)); + let cb04 = compile(|cb| nop(cb, 4)); + let cb05 = compile(|cb| nop(cb, 5)); + let cb06 = compile(|cb| nop(cb, 6)); + let cb07 = compile(|cb| nop(cb, 7)); + let cb08 = compile(|cb| nop(cb, 8)); + let cb09 = compile(|cb| nop(cb, 9)); + let cb10 = compile(|cb| nop(cb, 10)); + let cb11 = compile(|cb| nop(cb, 11)); + let cb12 = compile(|cb| nop(cb, 12)); + + assert_snapshot!(cb01.disasm(), @" 0x0: nop"); + assert_snapshot!(cb02.disasm(), @" 0x0: nop"); + assert_snapshot!(cb03.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb04.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb05.disasm(), @" 0x0: nop dword ptr [rax + rax]"); + assert_snapshot!(cb06.disasm(), @" 0x0: nop word ptr [rax + rax]"); + assert_snapshot!(cb07.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb08.disasm(), @" 0x0: nop dword ptr [rax + rax]"); + assert_snapshot!(cb09.disasm(), @" 0x0: nop word ptr [rax + rax]"); + assert_snapshot!(cb10.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop + "); + assert_snapshot!(cb11.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop + "); + assert_snapshot!(cb12.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop dword ptr [rax] + "); + + assert_snapshot!(cb01.string(), @"90"); + assert_snapshot!(cb02.string(), @"6690"); + assert_snapshot!(cb03.string(), @"0f1f00"); + assert_snapshot!(cb04.string(), @"0f1f4000"); + assert_snapshot!(cb05.string(), @"0f1f440000"); + assert_snapshot!(cb06.string(), @"660f1f440000"); + assert_snapshot!(cb07.string(), @"0f1f8000000000"); + assert_snapshot!(cb08.string(), @"0f1f840000000000"); + assert_snapshot!(cb09.string(), @"660f1f840000000000"); + assert_snapshot!(cb10.string(), @"660f1f84000000000090"); + assert_snapshot!(cb11.string(), @"660f1f8400000000006690"); + assert_snapshot!(cb12.string(), @"660f1f8400000000000f1f00"); } #[test] fn test_not() { - check_bytes("66f7d0", |cb| not(cb, AX)); - check_bytes("f7d0", |cb| not(cb, EAX)); - check_bytes("49f71424", |cb| not(cb, mem_opnd(64, R12, 0))); - check_bytes("f794242d010000", |cb| not(cb, mem_opnd(32, RSP, 301))); - check_bytes("f71424", |cb| not(cb, mem_opnd(32, RSP, 0))); - check_bytes("f7542403", |cb| not(cb, mem_opnd(32, RSP, 3))); - check_bytes("f75500", |cb| not(cb, mem_opnd(32, RBP, 0))); - check_bytes("f7550d", |cb| not(cb, mem_opnd(32, RBP, 13))); - check_bytes("48f7d0", |cb| not(cb, RAX)); - check_bytes("49f7d3", |cb| not(cb, R11)); - check_bytes("f710", |cb| not(cb, mem_opnd(32, RAX, 0))); - check_bytes("f716", |cb| not(cb, mem_opnd(32, RSI, 0))); - check_bytes("f717", |cb| not(cb, mem_opnd(32, RDI, 0))); - check_bytes("f75237", |cb| not(cb, mem_opnd(32, RDX, 55))); - check_bytes("f79239050000", |cb| not(cb, mem_opnd(32, RDX, 1337))); - check_bytes("f752c9", |cb| not(cb, mem_opnd(32, RDX, -55))); - check_bytes("f792d5fdffff", |cb| not(cb, mem_opnd(32, RDX, -555))); + let cb01 = compile(|cb| not(cb, AX)); + let cb02 = compile(|cb| not(cb, EAX)); + let cb03 = compile(|cb| not(cb, mem_opnd(64, R12, 0))); + let cb04 = compile(|cb| not(cb, mem_opnd(32, RSP, 301))); + let cb05 = compile(|cb| not(cb, mem_opnd(32, RSP, 0))); + let cb06 = compile(|cb| not(cb, mem_opnd(32, RSP, 3))); + let cb07 = compile(|cb| not(cb, mem_opnd(32, RBP, 0))); + let cb08 = compile(|cb| not(cb, mem_opnd(32, RBP, 13))); + let cb09 = compile(|cb| not(cb, RAX)); + let cb10 = compile(|cb| not(cb, R11)); + let cb11 = compile(|cb| not(cb, mem_opnd(32, RAX, 0))); + let cb12 = compile(|cb| not(cb, mem_opnd(32, RSI, 0))); + let cb13 = compile(|cb| not(cb, mem_opnd(32, RDI, 0))); + let cb14 = compile(|cb| not(cb, mem_opnd(32, RDX, 55))); + let cb15 = compile(|cb| not(cb, mem_opnd(32, RDX, 1337))); + let cb16 = compile(|cb| not(cb, mem_opnd(32, RDX, -55))); + let cb17 = compile(|cb| not(cb, mem_opnd(32, RDX, -555))); + + assert_snapshot!(cb01.disasm(), @" 0x0: not ax"); + assert_snapshot!(cb02.disasm(), @" 0x0: not eax"); + assert_snapshot!(cb03.disasm(), @" 0x0: not qword ptr [r12]"); + assert_snapshot!(cb04.disasm(), @" 0x0: not dword ptr [rsp + 0x12d]"); + assert_snapshot!(cb05.disasm(), @" 0x0: not dword ptr [rsp]"); + assert_snapshot!(cb06.disasm(), @" 0x0: not dword ptr [rsp + 3]"); + assert_snapshot!(cb07.disasm(), @" 0x0: not dword ptr [rbp]"); + assert_snapshot!(cb08.disasm(), @" 0x0: not dword ptr [rbp + 0xd]"); + assert_snapshot!(cb09.disasm(), @" 0x0: not rax"); + assert_snapshot!(cb10.disasm(), @" 0x0: not r11"); + assert_snapshot!(cb11.disasm(), @" 0x0: not dword ptr [rax]"); + assert_snapshot!(cb12.disasm(), @" 0x0: not dword ptr [rsi]"); + assert_snapshot!(cb13.disasm(), @" 0x0: not dword ptr [rdi]"); + assert_snapshot!(cb14.disasm(), @" 0x0: not dword ptr [rdx + 0x37]"); + assert_snapshot!(cb15.disasm(), @" 0x0: not dword ptr [rdx + 0x539]"); + assert_snapshot!(cb16.disasm(), @" 0x0: not dword ptr [rdx - 0x37]"); + assert_snapshot!(cb17.disasm(), @" 0x0: not dword ptr [rdx - 0x22b]"); + + assert_snapshot!(cb01.string(), @"66f7d0"); + assert_snapshot!(cb02.string(), @"f7d0"); + assert_snapshot!(cb03.string(), @"49f71424"); + assert_snapshot!(cb04.string(), @"f794242d010000"); + assert_snapshot!(cb05.string(), @"f71424"); + assert_snapshot!(cb06.string(), @"f7542403"); + assert_snapshot!(cb07.string(), @"f75500"); + assert_snapshot!(cb08.string(), @"f7550d"); + assert_snapshot!(cb09.string(), @"48f7d0"); + assert_snapshot!(cb10.string(), @"49f7d3"); + assert_snapshot!(cb11.string(), @"f710"); + assert_snapshot!(cb12.string(), @"f716"); + assert_snapshot!(cb13.string(), @"f717"); + assert_snapshot!(cb14.string(), @"f75237"); + assert_snapshot!(cb15.string(), @"f79239050000"); + assert_snapshot!(cb16.string(), @"f752c9"); + assert_snapshot!(cb17.string(), @"f792d5fdffff"); } #[test] fn test_or() { - check_bytes("09f2", |cb| or(cb, EDX, ESI)); + let cb = compile(|cb| or(cb, EDX, ESI)); + assert_snapshot!(cb.disasm(), @" 0x0: or edx, esi"); + assert_snapshot!(cb.string(), @"09f2"); } #[test] fn test_pop() { - check_bytes("58", |cb| pop(cb, RAX)); - check_bytes("5b", |cb| pop(cb, RBX)); - check_bytes("5c", |cb| pop(cb, RSP)); - check_bytes("5d", |cb| pop(cb, RBP)); - check_bytes("415c", |cb| pop(cb, R12)); - check_bytes("8f00", |cb| pop(cb, mem_opnd(64, RAX, 0))); - check_bytes("418f00", |cb| pop(cb, mem_opnd(64, R8, 0))); - check_bytes("418f4003", |cb| pop(cb, mem_opnd(64, R8, 3))); - check_bytes("8f44c803", |cb| pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); - check_bytes("418f44c803", |cb| pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + let cb01 = compile(|cb| pop(cb, RAX)); + let cb02 = compile(|cb| pop(cb, RBX)); + let cb03 = compile(|cb| pop(cb, RSP)); + let cb04 = compile(|cb| pop(cb, RBP)); + let cb05 = compile(|cb| pop(cb, R12)); + let cb06 = compile(|cb| pop(cb, mem_opnd(64, RAX, 0))); + let cb07 = compile(|cb| pop(cb, mem_opnd(64, R8, 0))); + let cb08 = compile(|cb| pop(cb, mem_opnd(64, R8, 3))); + let cb09 = compile(|cb| pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); + let cb10 = compile(|cb| pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + + assert_snapshot!(cb01.disasm(), @" 0x0: pop rax"); + assert_snapshot!(cb02.disasm(), @" 0x0: pop rbx"); + assert_snapshot!(cb03.disasm(), @" 0x0: pop rsp"); + assert_snapshot!(cb04.disasm(), @" 0x0: pop rbp"); + assert_snapshot!(cb05.disasm(), @" 0x0: pop r12"); + assert_snapshot!(cb06.disasm(), @" 0x0: pop qword ptr [rax]"); + assert_snapshot!(cb07.disasm(), @" 0x0: pop qword ptr [r8]"); + assert_snapshot!(cb08.disasm(), @" 0x0: pop qword ptr [r8 + 3]"); + assert_snapshot!(cb09.disasm(), @" 0x0: pop qword ptr [rax + rcx*8 + 3]"); + assert_snapshot!(cb10.disasm(), @" 0x0: pop qword ptr [r8 + rcx*8 + 3]"); + + assert_snapshot!(cb01.string(), @"58"); + assert_snapshot!(cb02.string(), @"5b"); + assert_snapshot!(cb03.string(), @"5c"); + assert_snapshot!(cb04.string(), @"5d"); + assert_snapshot!(cb05.string(), @"415c"); + assert_snapshot!(cb06.string(), @"8f00"); + assert_snapshot!(cb07.string(), @"418f00"); + assert_snapshot!(cb08.string(), @"418f4003"); + assert_snapshot!(cb09.string(), @"8f44c803"); + assert_snapshot!(cb10.string(), @"418f44c803"); } #[test] fn test_push() { - check_bytes("50", |cb| push(cb, RAX)); - check_bytes("53", |cb| push(cb, RBX)); - check_bytes("4154", |cb| push(cb, R12)); - check_bytes("ff30", |cb| push(cb, mem_opnd(64, RAX, 0))); - check_bytes("41ff30", |cb| push(cb, mem_opnd(64, R8, 0))); - check_bytes("41ff7003", |cb| push(cb, mem_opnd(64, R8, 3))); - check_bytes("ff74c803", |cb| push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); - check_bytes("41ff74c803", |cb| push(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + let cb1 = compile(|cb| push(cb, RAX)); + let cb2 = compile(|cb| push(cb, RBX)); + let cb3 = compile(|cb| push(cb, R12)); + let cb4 = compile(|cb| push(cb, mem_opnd(64, RAX, 0))); + let cb5 = compile(|cb| push(cb, mem_opnd(64, R8, 0))); + let cb6 = compile(|cb| push(cb, mem_opnd(64, R8, 3))); + let cb7 = compile(|cb| push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); + let cb8 = compile(|cb| push(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + + assert_snapshot!(cb1.disasm(), @" 0x0: push rax"); + assert_snapshot!(cb2.disasm(), @" 0x0: push rbx"); + assert_snapshot!(cb3.disasm(), @" 0x0: push r12"); + assert_snapshot!(cb4.disasm(), @" 0x0: push qword ptr [rax]"); + assert_snapshot!(cb5.disasm(), @" 0x0: push qword ptr [r8]"); + assert_snapshot!(cb6.disasm(), @" 0x0: push qword ptr [r8 + 3]"); + assert_snapshot!(cb7.disasm(), @" 0x0: push qword ptr [rax + rcx*8 + 3]"); + assert_snapshot!(cb8.disasm(), @" 0x0: push qword ptr [r8 + rcx*8 + 3]"); + + assert_snapshot!(cb1.string(), @"50"); + assert_snapshot!(cb2.string(), @"53"); + assert_snapshot!(cb3.string(), @"4154"); + assert_snapshot!(cb4.string(), @"ff30"); + assert_snapshot!(cb5.string(), @"41ff30"); + assert_snapshot!(cb6.string(), @"41ff7003"); + assert_snapshot!(cb7.string(), @"ff74c803"); + assert_snapshot!(cb8.string(), @"41ff74c803"); } #[test] fn test_ret() { - check_bytes("c3", ret); + let cb = compile(ret); + assert_snapshot!(cb.disasm(), @" 0x0: ret"); + assert_snapshot!(cb.string(), @"c3"); } #[test] fn test_sal() { - check_bytes("66d1e1", |cb| sal(cb, CX, uimm_opnd(1))); - check_bytes("d1e1", |cb| sal(cb, ECX, uimm_opnd(1))); - check_bytes("c1e505", |cb| sal(cb, EBP, uimm_opnd(5))); - check_bytes("d1642444", |cb| sal(cb, mem_opnd(32, RSP, 68), uimm_opnd(1))); - check_bytes("48d3e1", |cb| sal(cb, RCX, CL)); + let cb1 = compile(|cb| sal(cb, CX, uimm_opnd(1))); + let cb2 = compile(|cb| sal(cb, ECX, uimm_opnd(1))); + let cb3 = compile(|cb| sal(cb, EBP, uimm_opnd(5))); + let cb4 = compile(|cb| sal(cb, mem_opnd(32, RSP, 68), uimm_opnd(1))); + let cb5 = compile(|cb| sal(cb, RCX, CL)); + + assert_snapshot!(cb1.disasm(), @" 0x0: shl cx, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: shl ecx, 1"); + assert_snapshot!(cb3.disasm(), @" 0x0: shl ebp, 5"); + assert_snapshot!(cb4.disasm(), @" 0x0: shl dword ptr [rsp + 0x44], 1"); + assert_snapshot!(cb5.disasm(), @" 0x0: shl rcx, cl"); + + assert_snapshot!(cb1.string(), @"66d1e1"); + assert_snapshot!(cb2.string(), @"d1e1"); + assert_snapshot!(cb3.string(), @"c1e505"); + assert_snapshot!(cb4.string(), @"d1642444"); + assert_snapshot!(cb5.string(), @"48d3e1"); } #[test] fn test_sar() { - check_bytes("d1fa", |cb| sar(cb, EDX, uimm_opnd(1))); + let cb = compile(|cb| sar(cb, EDX, uimm_opnd(1))); + assert_snapshot!(cb.disasm(), @" 0x0: sar edx, 1"); + assert_snapshot!(cb.string(), @"d1fa"); } #[test] fn test_shr() { - check_bytes("49c1ee07", |cb| shr(cb, R14, uimm_opnd(7))); + let cb = compile(|cb| shr(cb, R14, uimm_opnd(7))); + assert_snapshot!(cb.disasm(), @" 0x0: shr r14, 7"); + assert_snapshot!(cb.string(), @"49c1ee07"); } #[test] fn test_sub() { - check_bytes("83e801", |cb| sub(cb, EAX, imm_opnd(1))); - check_bytes("4883e802", |cb| sub(cb, RAX, imm_opnd(2))); + let cb1 = compile(|cb| sub(cb, EAX, imm_opnd(1))); + let cb2 = compile(|cb| sub(cb, RAX, imm_opnd(2))); + + assert_snapshot!(cb1.disasm(), @" 0x0: sub eax, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: sub rax, 2"); + + assert_snapshot!(cb1.string(), @"83e801"); + assert_snapshot!(cb2.string(), @"4883e802"); } #[test] @@ -374,44 +757,95 @@ fn test_sub() { fn test_sub_uimm_too_large() { // This immediate becomes a different value after // sign extension, so not safe to encode. - check_bytes("ff", |cb| sub(cb, RCX, uimm_opnd(0x8000_0000))); + compile(|cb| sub(cb, RCX, uimm_opnd(0x8000_0000))); } #[test] fn test_test() { - check_bytes("84c0", |cb| test(cb, AL, AL)); - check_bytes("6685c0", |cb| test(cb, AX, AX)); - check_bytes("f6c108", |cb| test(cb, CL, uimm_opnd(8))); - check_bytes("f6c207", |cb| test(cb, DL, uimm_opnd(7))); - check_bytes("f6c108", |cb| test(cb, RCX, uimm_opnd(8))); - check_bytes("f6420808", |cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(8))); - check_bytes("f64208ff", |cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(255))); - check_bytes("66f7c2ffff", |cb| test(cb, DX, uimm_opnd(0xffff))); - check_bytes("66f74208ffff", |cb| test(cb, mem_opnd(16, RDX, 8), uimm_opnd(0xffff))); - check_bytes("f60601", |cb| test(cb, mem_opnd(8, RSI, 0), uimm_opnd(1))); - check_bytes("f6461001", |cb| test(cb, mem_opnd(8, RSI, 16), uimm_opnd(1))); - check_bytes("f646f001", |cb| test(cb, mem_opnd(8, RSI, -16), uimm_opnd(1))); - check_bytes("854640", |cb| test(cb, mem_opnd(32, RSI, 64), EAX)); - check_bytes("4885472a", |cb| test(cb, mem_opnd(64, RDI, 42), RAX)); - check_bytes("4885c0", |cb| test(cb, RAX, RAX)); - check_bytes("4885f0", |cb| test(cb, RAX, RSI)); - check_bytes("48f74640f7ffffff", |cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08))); - check_bytes("48f7464008000000", |cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(0x08))); - check_bytes("48f7c108000000", |cb| test(cb, RCX, imm_opnd(0x08))); - //check_bytes("48a9f7ffff0f", |cb| test(cb, RAX, imm_opnd(0x0FFFFFF7))); + let cb01 = compile(|cb| test(cb, AL, AL)); + let cb02 = compile(|cb| test(cb, AX, AX)); + let cb03 = compile(|cb| test(cb, CL, uimm_opnd(8))); + let cb04 = compile(|cb| test(cb, DL, uimm_opnd(7))); + let cb05 = compile(|cb| test(cb, RCX, uimm_opnd(8))); + let cb06 = compile(|cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(8))); + let cb07 = compile(|cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(255))); + let cb08 = compile(|cb| test(cb, DX, uimm_opnd(0xffff))); + let cb09 = compile(|cb| test(cb, mem_opnd(16, RDX, 8), uimm_opnd(0xffff))); + let cb10 = compile(|cb| test(cb, mem_opnd(8, RSI, 0), uimm_opnd(1))); + let cb11 = compile(|cb| test(cb, mem_opnd(8, RSI, 16), uimm_opnd(1))); + let cb12 = compile(|cb| test(cb, mem_opnd(8, RSI, -16), uimm_opnd(1))); + let cb13 = compile(|cb| test(cb, mem_opnd(32, RSI, 64), EAX)); + let cb14 = compile(|cb| test(cb, mem_opnd(64, RDI, 42), RAX)); + let cb15 = compile(|cb| test(cb, RAX, RAX)); + let cb16 = compile(|cb| test(cb, RAX, RSI)); + let cb17 = compile(|cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08))); + let cb18 = compile(|cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(0x08))); + let cb19 = compile(|cb| test(cb, RCX, imm_opnd(0x08))); + + assert_snapshot!(cb01.disasm(), @" 0x0: test al, al"); + assert_snapshot!(cb02.disasm(), @" 0x0: test ax, ax"); + assert_snapshot!(cb03.disasm(), @" 0x0: test cl, 8"); + assert_snapshot!(cb04.disasm(), @" 0x0: test dl, 7"); + assert_snapshot!(cb05.disasm(), @" 0x0: test cl, 8"); + assert_snapshot!(cb06.disasm(), @" 0x0: test byte ptr [rdx + 8], 8"); + assert_snapshot!(cb07.disasm(), @" 0x0: test byte ptr [rdx + 8], 0xff"); + assert_snapshot!(cb08.disasm(), @" 0x0: test dx, 0xffff"); + assert_snapshot!(cb09.disasm(), @" 0x0: test word ptr [rdx + 8], 0xffff"); + assert_snapshot!(cb10.disasm(), @" 0x0: test byte ptr [rsi], 1"); + assert_snapshot!(cb11.disasm(), @" 0x0: test byte ptr [rsi + 0x10], 1"); + assert_snapshot!(cb12.disasm(), @" 0x0: test byte ptr [rsi - 0x10], 1"); + assert_snapshot!(cb13.disasm(), @" 0x0: test dword ptr [rsi + 0x40], eax"); + assert_snapshot!(cb14.disasm(), @" 0x0: test qword ptr [rdi + 0x2a], rax"); + assert_snapshot!(cb15.disasm(), @" 0x0: test rax, rax"); + assert_snapshot!(cb16.disasm(), @" 0x0: test rax, rsi"); + assert_snapshot!(cb17.disasm(), @" 0x0: test qword ptr [rsi + 0x40], -9"); + assert_snapshot!(cb18.disasm(), @" 0x0: test qword ptr [rsi + 0x40], 8"); + assert_snapshot!(cb19.disasm(), @" 0x0: test rcx, 8"); + + assert_snapshot!(cb01.string(), @"84c0"); + assert_snapshot!(cb02.string(), @"6685c0"); + assert_snapshot!(cb03.string(), @"f6c108"); + assert_snapshot!(cb04.string(), @"f6c207"); + assert_snapshot!(cb05.string(), @"f6c108"); + assert_snapshot!(cb06.string(), @"f6420808"); + assert_snapshot!(cb07.string(), @"f64208ff"); + assert_snapshot!(cb08.string(), @"66f7c2ffff"); + assert_snapshot!(cb09.string(), @"66f74208ffff"); + assert_snapshot!(cb10.string(), @"f60601"); + assert_snapshot!(cb11.string(), @"f6461001"); + assert_snapshot!(cb12.string(), @"f646f001"); + assert_snapshot!(cb13.string(), @"854640"); + assert_snapshot!(cb14.string(), @"4885472a"); + assert_snapshot!(cb15.string(), @"4885c0"); + assert_snapshot!(cb16.string(), @"4885f0"); + assert_snapshot!(cb17.string(), @"48f74640f7ffffff"); + assert_snapshot!(cb18.string(), @"48f7464008000000"); + assert_snapshot!(cb19.string(), @"48f7c108000000"); } #[test] fn test_xchg() { - check_bytes("4891", |cb| xchg(cb, RAX, RCX)); - check_bytes("4995", |cb| xchg(cb, RAX, R13)); - check_bytes("4887d9", |cb| xchg(cb, RCX, RBX)); - check_bytes("4d87f9", |cb| xchg(cb, R9, R15)); + let cb1 = compile(|cb| xchg(cb, RAX, RCX)); + let cb2 = compile(|cb| xchg(cb, RAX, R13)); + let cb3 = compile(|cb| xchg(cb, RCX, RBX)); + let cb4 = compile(|cb| xchg(cb, R9, R15)); + + assert_snapshot!(cb1.disasm(), @" 0x0: xchg rcx, rax"); + assert_snapshot!(cb2.disasm(), @" 0x0: xchg r13, rax"); + assert_snapshot!(cb3.disasm(), @" 0x0: xchg rcx, rbx"); + assert_snapshot!(cb4.disasm(), @" 0x0: xchg r9, r15"); + + assert_snapshot!(cb1.string(), @"4891"); + assert_snapshot!(cb2.string(), @"4995"); + assert_snapshot!(cb3.string(), @"4887d9"); + assert_snapshot!(cb4.string(), @"4d87f9"); } #[test] fn test_xor() { - check_bytes("31c0", |cb| xor(cb, EAX, EAX)); + let cb = compile(|cb| xor(cb, EAX, EAX)); + assert_snapshot!(cb.disasm(), @" 0x0: xor eax, eax"); + assert_snapshot!(cb.string(), @"31c0"); } #[test] @@ -437,25 +871,3 @@ fn basic_capstone_usage() -> std::result::Result<(), capstone::Error> { )), } } - -#[test] -#[ignore] -#[cfg(feature = "disasm")] -fn block_comments() { - let mut cb = super::CodeBlock::new_dummy(); - - let first_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Beginning"); - xor(&mut cb, EAX, EAX); // 2 bytes long - let second_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Two bytes in"); - cb.add_comment("Still two bytes in"); - cb.add_comment("Still two bytes in"); // Duplicate, should be ignored - test(&mut cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08)); // 8 bytes long - let third_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Ten bytes in"); - - assert_eq!(&vec!( "Beginning".to_string() ), cb.comments_at(first_write_ptr).unwrap()); - assert_eq!(&vec!( "Two bytes in".to_string(), "Still two bytes in".to_string() ), cb.comments_at(second_write_ptr).unwrap()); - assert_eq!(&vec!( "Ten bytes in".to_string() ), cb.comments_at(third_write_ptr).unwrap()); -} diff --git a/zjit/src/assertions.rs b/zjit/src/assertions.rs deleted file mode 100644 index 0dacc938fc5724..00000000000000 --- a/zjit/src/assertions.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Assert that CodeBlock has the code specified with hex. In addition, if tested with -/// `cargo test --all-features`, it also checks it generates the specified disasm. -#[cfg(test)] -macro_rules! assert_disasm { - ($cb:expr, $hex:expr, $disasm:expr) => { - #[cfg(feature = "disasm")] - { - use $crate::disasm::disasm_addr_range; - use $crate::cruby::unindent; - let disasm = disasm_addr_range( - &$cb, - $cb.get_ptr(0).raw_addr(&$cb), - $cb.get_write_ptr().raw_addr(&$cb), - ); - assert_eq!(unindent(&disasm, false), unindent(&$disasm, true)); - } - assert_eq!(format!("{:x}", $cb), $hex); - }; -} -#[cfg(test)] -pub(crate) use assert_disasm; diff --git a/zjit/src/backend/arm64/mod.rs b/zjit/src/backend/arm64/mod.rs index 50e7074de11222..b1b898f38d913b 100644 --- a/zjit/src/backend/arm64/mod.rs +++ b/zjit/src/backend/arm64/mod.rs @@ -1425,7 +1425,7 @@ fn merge_three_reg_mov( #[cfg(test)] mod tests { use super::*; - use crate::assertions::assert_disasm; + use insta::assert_snapshot; static TEMP_REGS: [Reg; 5] = [X1_REG, X9_REG, X10_REG, X14_REG, X15_REG]; @@ -1441,11 +1441,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "600080d2207d009be10300aa", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #3 0x4: mul x0, x9, x0 0x8: mov x1, x0 - "}); + "); + assert_snapshot!(cb.string(), @"600080d2207d009be10300aa"); } #[test] @@ -1459,10 +1460,11 @@ mod tests { asm.mov(sp, new_sp); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "ff830091ff8300d1", " + assert_snapshot!(cb.disasm(), @" 0x0: add sp, sp, #0x20 0x4: sub sp, sp, #0x20 "); + assert_snapshot!(cb.string(), @"ff830091ff8300d1"); } #[test] @@ -1474,10 +1476,11 @@ mod tests { asm.add_into(Opnd::Reg(X20_REG), 0x20.into()); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "ff230091948200b1", " + assert_snapshot!(cb.disasm(), @" 0x0: add sp, sp, #8 0x4: adds x20, x20, #0x20 "); + assert_snapshot!(cb.string(), @"ff230091948200b1"); } #[test] @@ -1488,11 +1491,12 @@ mod tests { asm.load_into(Opnd::Reg(X1_REG), difference); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000180d2000005ebe10300aa", " + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #8 0x4: subs x0, x0, x5 0x8: mov x1, x0 "); + assert_snapshot!(cb.string(), @"000180d2000005ebe10300aa"); } #[test] @@ -1503,10 +1507,11 @@ mod tests { asm.cret(ret_val); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000040f8c0035fd6", " + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x0] 0x4: ret "); + assert_snapshot!(cb.string(), @"000040f8c0035fd6"); } #[test] @@ -1567,7 +1572,7 @@ mod tests { asm.frame_setup(THREE_REGS, 3); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1578,6 +1583,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 3 preserved regs (odd), even slot_count @@ -1586,7 +1592,7 @@ mod tests { asm.frame_setup(THREE_REGS, 4); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1597,6 +1603,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 4 preserved regs (even), odd slot_count @@ -1606,7 +1613,7 @@ mod tests { asm.frame_setup(FOUR_REGS, 3); asm.frame_teardown(FOUR_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1617,6 +1624,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8"); } } @@ -1656,7 +1664,7 @@ mod tests { } asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b", " + assert_snapshot!(cb.disasm(), @r" 0x0: orr x0, xzr, #0x7fffffff 0x4: add x0, sp, x0 0x8: mov x0, #8 @@ -1676,6 +1684,7 @@ mod tests { 0x40: orr x0, xzr, #0xffffffff80000000 0x44: add x0, sp, x0 "); + assert_snapshot!(cb.string(), @"e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b"); } #[test] @@ -1690,7 +1699,7 @@ mod tests { asm.store(large_mem, large_mem); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8", " + assert_snapshot!(cb.disasm(), @" 0x0: sub x16, sp, #0x305 0x4: ldur x16, [x16] 0x8: stur x16, [x0] @@ -1702,6 +1711,7 @@ mod tests { 0x20: sub x17, sp, #0x305 0x24: stur x16, [x17] "); + assert_snapshot!(cb.string(), @"f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8"); } #[test] @@ -1717,13 +1727,14 @@ mod tests { let gc_offsets = asm.arm64_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_disasm!(cb, "50000058030000140010000000000000b00200f8", " + assert_snapshot!(cb.disasm(), @" 0x0: ldr x16, #8 0x4: b #0x10 0x8: .byte 0x00, 0x10, 0x00, 0x00 0xc: .byte 0x00, 0x00, 0x00, 0x00 0x10: stur x16, [x21] "); + assert_snapshot!(cb.string(), @"50000058030000140010000000000000b00200f8"); } #[test] @@ -1968,10 +1979,11 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000001ca400000f8", " + assert_snapshot!(cb.disasm(), @" 0x0: eor x0, x0, x1 0x4: stur x0, [x2] "); + assert_snapshot!(cb.string(), @"000001ca400000f8"); } #[test] @@ -2005,9 +2017,8 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::mem(64, CFP, 8)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "618240f8", {" - 0x0: ldur x1, [x19, #8] - "}); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x1, [x19, #8]"); + assert_snapshot!(cb.string(), @"618240f8"); } #[test] @@ -2018,10 +2029,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::UImm(0x10000)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "e1ff9fd2e10370b2", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x1, #0xffff 0x4: orr x1, xzr, #0x10000 - "}); + "); + assert_snapshot!(cb.string(), @"e1ff9fd2e10370b2"); } #[test] @@ -2032,11 +2044,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "800280d2010080d201b0819a", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #0x14 0x4: mov x1, #0 0x8: csel x1, x0, x1, lt - "}); + "); + assert_snapshot!(cb.string(), @"800280d2010080d201b0819a"); } #[test] @@ -2074,10 +2087,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "200500b1010400b1", {" + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x9, #1 0x4: adds x1, x0, #1 - "}); + "); + assert_snapshot!(cb.string(), @"200500b1010400b1"); } #[test] @@ -2091,10 +2105,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, #0 0x4: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"100080d200023fd6"); } #[test] @@ -2110,13 +2125,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00300aae00301aae10310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x16 0xc: mov x16, #0 0x10: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2133,7 +2149,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x2 0x4: mov x2, x3 0x8: mov x3, x16 @@ -2142,7 +2158,8 @@ mod tests { 0x14: mov x1, x16 0x18: mov x16, #0 0x1c: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2158,14 +2175,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00300aae00301aae10302aae20310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x2 0xc: mov x2, x16 0x10: mov x16, #0 0x14: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00300aae00301aae10302aae20310aa100080d200023fd6"); } - } diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index b18510c29a2972..04430955096048 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -919,7 +919,7 @@ impl Assembler #[cfg(test)] mod tests { - use crate::assertions::assert_disasm; + use insta::assert_snapshot; use super::*; fn setup_asm() -> (Assembler, CodeBlock) { @@ -934,7 +934,11 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881c0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: add rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881c0ff000000"); } #[test] @@ -945,7 +949,12 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c01d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: add rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c01d8"); } #[test] @@ -956,7 +965,11 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881e0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: and rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881e0ff000000"); } #[test] @@ -967,7 +980,12 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c21d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: and rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c21d8"); } #[test] @@ -977,9 +995,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "4881f8ff000000", " - 0x0: cmp rax, 0xff - "); + assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, 0xff"); + assert_snapshot!(cb.string(), @"4881f8ff000000"); } #[test] @@ -989,10 +1006,11 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "49bbffffffffffff00004c39d8", " - 0x0: movabs r11, 0xffffffffffff - 0xa: cmp rax, r11 + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: cmp rax, r11 "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1002,9 +1020,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "4883f8ff", " - 0x0: cmp rax, -1 - "); + assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, -1"); + assert_snapshot!(cb.string(), @"4883f8ff"); } #[test] @@ -1016,7 +1033,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "6681780600f0"); + assert_snapshot!(cb.disasm(), @" 0x0: cmp word ptr [rax + 6], 0xf000"); + assert_snapshot!(cb.string(), @"6681780600f0"); } #[test] @@ -1028,7 +1046,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000_0000)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "817804000000f0"); + assert_snapshot!(cb.disasm(), @" 0x0: cmp dword ptr [rax + 4], 0xf0000000"); + assert_snapshot!(cb.string(), @"817804000000f0"); } #[test] @@ -1039,7 +1058,11 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881c8ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: or rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881c8ff000000"); } #[test] @@ -1050,7 +1073,12 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c09d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: or rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c09d8"); } #[test] @@ -1061,7 +1089,11 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881e8ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: sub rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881e8ff000000"); } #[test] @@ -1072,7 +1104,12 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c29d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: sub rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c29d8"); } #[test] @@ -1082,9 +1119,8 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "48f7c0ff000000", " - 0x0: test rax, 0xff - "); + assert_snapshot!(cb.disasm(), @" 0x0: test rax, 0xff"); + assert_snapshot!(cb.string(), @"48f7c0ff000000"); } #[test] @@ -1094,7 +1130,11 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "49bbffffffffffff00004c85d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: test rax, r11 + "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c85d8"); } #[test] @@ -1105,7 +1145,11 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881f0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: xor rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881f0ff000000"); } #[test] @@ -1116,7 +1160,12 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c31d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: xor rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c31d8"); } #[test] @@ -1127,9 +1176,8 @@ mod tests { asm.mov(SP, sp); // should be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "488d5b08", {" - 0x0: lea rbx, [rbx + 8] - "}); + assert_snapshot!(cb.disasm(), @" 0x0: lea rbx, [rbx + 8]"); + assert_snapshot!(cb.string(), @"488d5b08"); } #[test] @@ -1141,10 +1189,11 @@ mod tests { asm.mov(Opnd::mem(64, SP, 0), sp); // should NOT be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "488d4308488903", {" - 0x0: lea rax, [rbx + 8] - 0x4: mov qword ptr [rbx], rax - "}); + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: cmp rax, r11 + "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1158,7 +1207,15 @@ mod tests { asm.mov(Opnd::Reg(RAX_REG), result); asm.compile_with_num_regs(&mut cb, 2); - assert_eq!(format!("{:x}", cb), "488b43084885c0b814000000b900000000480f45c14889c0"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, qword ptr [rbx + 8] + 0x4: test rax, rax + 0x7: mov eax, 0x14 + 0xc: mov ecx, 0 + 0x11: cmovne rax, rcx + 0x15: mov rax, rax + "); + assert_snapshot!(cb.string(), @"488b43084885c0b814000000b900000000480f45c14889c0"); } #[test] @@ -1169,9 +1226,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983c540", {" - 0x0: add r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); + assert_snapshot!(cb.string(), @"4983c540"); } #[test] @@ -1181,9 +1237,8 @@ mod tests { asm.add_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983c540", {" - 0x0: add r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); + assert_snapshot!(cb.string(), @"4983c540"); } #[test] @@ -1194,9 +1249,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983ed40", {" - 0x0: sub r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); + assert_snapshot!(cb.string(), @"4983ed40"); } #[test] @@ -1206,9 +1260,8 @@ mod tests { asm.sub_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983ed40", {" - 0x0: sub r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); + assert_snapshot!(cb.string(), @"4983ed40"); } #[test] @@ -1219,7 +1272,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983e540"); + assert_snapshot!(cb.disasm(), @" 0x0: and r13, 0x40"); + assert_snapshot!(cb.string(), @"4983e540"); } #[test] @@ -1230,7 +1284,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983cd40"); + assert_snapshot!(cb.disasm(), @" 0x0: or r13, 0x40"); + assert_snapshot!(cb.string(), @"4983cd40"); } #[test] @@ -1241,7 +1296,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983f540"); + assert_snapshot!(cb.disasm(), @" 0x0: xor r13, 0x40"); + assert_snapshot!(cb.string(), @"4983f540"); } #[test] @@ -1255,10 +1311,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "b800000000ffd0", {" - 0x0: mov eax, 0 - 0x5: call rax - "}); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov eax, 0 + 0x5: call rax + "); + assert_snapshot!(cb.string(), @"b800000000ffd0"); } #[test] @@ -1274,13 +1331,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889fe4c89dfb800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 0x9: mov eax, 0 0xe: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889fe4c89dfb800000000ffd0"); } #[test] @@ -1297,7 +1355,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 @@ -1306,7 +1364,8 @@ mod tests { 0xf: mov rdx, r11 0x12: mov eax, 0 0x17: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1322,14 +1381,15 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889d64889fa4c89dfb800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdx 0x6: mov rdx, rdi 0x9: mov rdi, r11 0xc: mov eax, 0 0x11: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889d64889fa4c89dfb800000000ffd0"); } #[test] @@ -1349,7 +1409,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, 3); - assert_disasm!(cb, "b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov eax, 1 0x5: mov ecx, 2 0xa: mov edx, 3 @@ -1360,7 +1420,8 @@ mod tests { 0x1b: mov rdx, r11 0x1e: mov eax, 0 0x23: call rax - "}); + "); + assert_snapshot!(cb.string(), @"b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1377,12 +1438,13 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "48837b1001bf04000000480f4f3b48893b", {" + assert_snapshot!(cb.disasm(), @" 0x0: cmp qword ptr [rbx + 0x10], 1 0x5: mov edi, 4 0xa: cmovg rdi, qword ptr [rbx] 0xe: mov qword ptr [rbx], rdi - "}); + "); + assert_snapshot!(cb.string(), @"48837b1001bf04000000480f4f3b48893b"); } #[test] @@ -1396,12 +1458,13 @@ mod tests { asm.compile_with_num_regs(&mut cb, 3); - assert_disasm!(cb, "48b830198dc8227f0000b904000000480f44c1488903", {" + assert_snapshot!(cb.disasm(), @" 0x0: movabs rax, 0x7f22c88d1930 0xa: mov ecx, 4 0xf: cmove rax, rcx 0x13: mov qword ptr [rbx], rax - "}); + "); + assert_snapshot!(cb.string(), @"48b830198dc8227f0000b904000000480f44c1488903"); } #[test] @@ -1413,10 +1476,11 @@ mod tests { asm.mov(shape_opnd, Opnd::Imm(0x8000_0001)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "c70001000080c70001000080", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov dword ptr [rax], 0x80000001 0x6: mov dword ptr [rax], 0x80000001 - "}); + "); + assert_snapshot!(cb.string(), @"c70001000080c70001000080"); } #[test] @@ -1431,7 +1495,7 @@ mod tests { asm.frame_teardown(&[]); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d", {" + assert_snapshot!(cb.disasm(), @" 0x0: push rbp 0x1: mov rbp, rsp 0x4: push r13 @@ -1449,7 +1513,8 @@ mod tests { 0x22: sub rsp, 0x30 0x26: mov rsp, rbp 0x29: pop rbp - "}); + "); + assert_snapshot!(cb.string(), @"554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d"); } #[test] @@ -1463,9 +1528,10 @@ mod tests { let gc_offsets = asm.x86_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_disasm!(cb, "49bb00100000000000004c891b", " + assert_snapshot!(cb.disasm(), @" 0x0: movabs r11, 0x1000 0xa: mov qword ptr [rbx], r11 "); + assert_snapshot!(cb.string(), @"49bb00100000000000004c891b"); } } diff --git a/zjit/src/lib.rs b/zjit/src/lib.rs index e6f743fa1e6782..e58cf2bec4787b 100644 --- a/zjit/src/lib.rs +++ b/zjit/src/lib.rs @@ -26,7 +26,5 @@ mod disasm; mod options; mod profile; mod invariants; -#[cfg(test)] -mod assertions; mod bitset; mod gc; From b082d672533a6c0cf69c39497342cb2d5dde9f12 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 19 Sep 2025 22:13:09 +0900 Subject: [PATCH 02/22] [ruby/prism] Fix dangling pointers on Windows as well Share the empty source string in `pm_string_mapped_init` and `pm_string_file_init`. https://github.com/ruby/prism/commit/f7a9a03a92 --- prism/util/pm_string.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c index cf79885fddbdff..a7493c468b166e 100644 --- a/prism/util/pm_string.c +++ b/prism/util/pm_string.c @@ -1,5 +1,7 @@ #include "prism/util/pm_string.h" +static const uint8_t empty_source[] = ""; + /** * Returns the size of the pm_string_t struct. This is necessary to allocate the * correct amount of memory in the FFI backend. @@ -133,8 +135,7 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { // the source to a constant empty string and return. if (file_size == 0) { pm_string_file_handle_close(&handle); - const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; + *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; return PM_STRING_INIT_SUCCESS; } @@ -182,8 +183,7 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { if (size == 0) { close(fd); - static const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; + *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; return PM_STRING_INIT_SUCCESS; } @@ -225,8 +225,7 @@ pm_string_file_init(pm_string_t *string, const char *filepath) { // the source to a constant empty string and return. if (file_size == 0) { pm_string_file_handle_close(&handle); - const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; + *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; return PM_STRING_INIT_SUCCESS; } @@ -278,8 +277,7 @@ pm_string_file_init(pm_string_t *string, const char *filepath) { size_t size = (size_t) sb.st_size; if (size == 0) { close(fd); - static const uint8_t source[] = ""; - *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; + *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 }; return PM_STRING_INIT_SUCCESS; } From 1663e2fbc8f3e904266ee89ba17066c3673765a0 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 19 Sep 2025 09:00:58 -0400 Subject: [PATCH 03/22] Fix capacity of imemo_fields objects created from rb_imemo_fields_new_complex_tbl The imemo_fields_new function takes a capacity in the number of fields to preallocate. rb_imemo_fields_new_complex_tbl is using it incorrectly because it is preallocating sizeof(struct rb_fields) number of fields. --- imemo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imemo.c b/imemo.c index 5a5ec4a4d382e8..346fae3b869ca0 100644 --- a/imemo.c +++ b/imemo.c @@ -153,7 +153,7 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg) VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl) { - VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields)); + VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields)); IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl; FL_SET_RAW(fields, OBJ_FIELD_HEAP); st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields); From e40cd392e44c38ce93c573b9244f46bba868c09c Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 11:56:59 -0400 Subject: [PATCH 04/22] ZJIT: Measure reading/writing locals with level > 0 (#14601) ZJIT: Measure writing to locals with level > 0 --- zjit.rb | 2 ++ zjit/src/codegen.rs | 6 ++++++ zjit/src/stats.rs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/zjit.rb b/zjit.rb index 42cfe1cb91bea4..e3d9d4c728f459 100644 --- a/zjit.rb +++ b/zjit.rb @@ -64,6 +64,8 @@ def stats_string :vm_write_sp_count, :vm_write_locals_count, :vm_write_stack_count, + :vm_write_to_parent_iseq_local_count, + :vm_read_from_parent_iseq_local_count, :code_region_bytes, :side_exit_count, diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 165e68c791e190..e0fd6cf2bd546e 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -532,6 +532,9 @@ fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -> lir::Opnd { + if level > 0 { + gen_incr_counter(asm, Counter::vm_read_from_parent_iseq_local_count); + } let ep = gen_get_ep(asm, level); let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32"))); asm.load(Opnd::mem(64, ep, offset)) @@ -541,6 +544,9 @@ fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) - /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) { + if level > 0 { + gen_incr_counter(asm, Counter::vm_write_to_parent_iseq_local_count); + } let ep = gen_get_ep(asm, level); // When we've proved that we're writing an immediate, diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 0a0daa5d9c54d6..6fed5cf559bbea 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -156,6 +156,10 @@ make_counters! { vm_write_sp_count, vm_write_locals_count, vm_write_stack_count, + vm_write_to_parent_iseq_local_count, + vm_read_from_parent_iseq_local_count, + // TODO(max): Implement + // vm_reify_stack_count, } /// Increase a counter by a specified amount From f0702c5aa32aa7092a4bb6c0c3e5863c4411e22d Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 08:57:33 -0400 Subject: [PATCH 05/22] ZJIT: Also count fallback sends to ISEQs we can't direct send to Make sure these parameter types are counted in the fallback def_types. --- zjit/src/hir.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 48cbd423b3cd95..1fdef0e404a4be 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -1864,6 +1864,9 @@ impl Function { // TODO(max): Handle other kinds of parameter passing let iseq = unsafe { get_def_iseq_ptr((*cme).def) }; if !can_direct_send(iseq) { + if let Insn::SendWithoutBlock { def_type: insn_def_type, .. } = &mut self.insns[insn_id.0] { + *insn_def_type = Some(MethodType::from(def_type)); + } self.push_insn_id(block, insn_id); continue; } self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state }); From d7ad44613723201a4c218aabae5baa7585a9867e Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 09:01:05 -0400 Subject: [PATCH 06/22] ZJIT: Count method sends where method lookup fails --- zjit/src/hir.rs | 4 ++++ zjit/src/stats.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 1fdef0e404a4be..08bdd5311f60a2 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -481,6 +481,7 @@ pub enum MethodType { Optimized, Missing, Refined, + Null, } impl From for MethodType { @@ -1852,6 +1853,9 @@ impl Function { // Do method lookup let mut cme = unsafe { rb_callable_method_entry(klass, mid) }; if cme.is_null() { + if let Insn::SendWithoutBlock { def_type: insn_def_type, .. } = &mut self.insns[insn_id.0] { + *insn_def_type = Some(MethodType::Null); + } self.push_insn_id(block, insn_id); continue; } // Load an overloaded cme if applicable. See vm_search_cc(). diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 6fed5cf559bbea..012b8be250b43f 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -150,6 +150,7 @@ make_counters! { send_fallback_optimized, send_fallback_missing, send_fallback_refined, + send_fallback_null, // Writes to the VM frame vm_write_pc_count, @@ -263,6 +264,7 @@ pub fn send_fallback_counter(def_type: crate::hir::MethodType) -> Counter { Optimized => send_fallback_optimized, Missing => send_fallback_missing, Refined => send_fallback_refined, + Null => send_fallback_null, } } From 71067aa54c9fd819313dd2d35cb5b32803a65ad4 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 17 Sep 2025 19:06:55 +0200 Subject: [PATCH 07/22] [ruby/prism] Reject argument command call taking a block with more trailing arguments https://bugs.ruby-lang.org/issues/21168#note-5 The added code samples align with `parse.y`, except for `foo(bar baz do end)` which `parse.y` currently rejects but shouldn't. https://github.com/ruby/prism/commit/3a4e102d80 --- prism/prism.c | 11 +++++++++ test/prism/errors/command_calls.txt | 7 ++++++ test/prism/errors/command_calls_34.txt | 24 +++++++++++++++++++ test/prism/fixtures/command_method_call_2.txt | 3 +++ test/prism/fixtures_test.rb | 2 ++ test/prism/lex_test.rb | 3 +++ test/prism/ruby/parser_test.rb | 3 +++ test/prism/ruby/ripper_test.rb | 3 +++ test/prism/ruby/ruby_parser_test.rb | 3 +++ 9 files changed, 59 insertions(+) create mode 100644 test/prism/errors/command_calls_34.txt create mode 100644 test/prism/fixtures/command_method_call_2.txt diff --git a/prism/prism.c b/prism/prism.c index 42a821e53584a9..6dd0b2ae738588 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -14443,6 +14443,17 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for if (accepted_newline) { pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA); } + + // If this is a command call and an argument takes a block, + // there can be no further arguments. For example, + // `foo(bar 1 do end, 2)` should be rejected. + if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) { + pm_call_node_t *call = (pm_call_node_t *) argument; + if (call->opening_loc.start == NULL && call->arguments != NULL && call->block != NULL) { + pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA); + break; + } + } } else { // If there is no comma at the end of the argument list then we're // done parsing arguments and can break out of this loop. diff --git a/test/prism/errors/command_calls.txt b/test/prism/errors/command_calls.txt index 19812a1d0a6780..6601e5fbbc622c 100644 --- a/test/prism/errors/command_calls.txt +++ b/test/prism/errors/command_calls.txt @@ -1,3 +1,10 @@ [a b] ^ unexpected local variable or method; expected a `,` separator for the array elements + +[ + a b do + ^ unexpected local variable or method; expected a `,` separator for the array elements + end, +] + diff --git a/test/prism/errors/command_calls_34.txt b/test/prism/errors/command_calls_34.txt new file mode 100644 index 00000000000000..ce62bc1492a3a0 --- /dev/null +++ b/test/prism/errors/command_calls_34.txt @@ -0,0 +1,24 @@ +foo(bar 1 do end, 2) + ^ invalid comma + ^ unexpected integer; expected a `)` to close the arguments + ^ unexpected integer, expecting end-of-input + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +foo(bar 1 do end,) + ^ invalid comma + +foo(1, bar 2 do end) + ^ unexpected integer; expected a `)` to close the arguments + ^ unexpected integer, expecting end-of-input + ^~ unexpected 'do', expecting end-of-input + ^~ unexpected 'do', ignoring it + ^~~ unexpected 'end', ignoring it + ^ unexpected ')', ignoring it + +foo(1, bar 2) + ^ unexpected integer; expected a `)` to close the arguments + ^ unexpected integer, expecting end-of-input + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + diff --git a/test/prism/fixtures/command_method_call_2.txt b/test/prism/fixtures/command_method_call_2.txt new file mode 100644 index 00000000000000..165c45987aa944 --- /dev/null +++ b/test/prism/fixtures/command_method_call_2.txt @@ -0,0 +1,3 @@ +foo(bar baz do end) + +foo(bar baz, bat) diff --git a/test/prism/fixtures_test.rb b/test/prism/fixtures_test.rb index b4b656fcf49b48..ddb6ffb40c6632 100644 --- a/test/prism/fixtures_test.rb +++ b/test/prism/fixtures_test.rb @@ -27,6 +27,8 @@ class FixturesTest < TestCase # Leaving these out until they are supported by parse.y. except << "leading_logical.txt" except << "endless_methods_command_call.txt" + # https://bugs.ruby-lang.org/issues/21168#note-5 + except << "command_method_call_2.txt" Fixture.each(except: except) do |fixture| define_method(fixture.test_name) { assert_valid_syntax(fixture.read) } diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb index 4eacbab3e1170d..3a0da1a2d87d67 100644 --- a/test/prism/lex_test.rb +++ b/test/prism/lex_test.rb @@ -48,6 +48,9 @@ class LexTest < TestCase # https://bugs.ruby-lang.org/issues/17398#note-12 except << "endless_methods_command_call.txt" + # https://bugs.ruby-lang.org/issues/21168#note-5 + except << "command_method_call_2.txt" + Fixture.each(except: except) do |fixture| define_method(fixture.test_name) { assert_lex(fixture) } end diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb index 98740f09734043..10b5fca5eaefef 100644 --- a/test/prism/ruby/parser_test.rb +++ b/test/prism/ruby/parser_test.rb @@ -70,6 +70,9 @@ class ParserTest < TestCase # Ruby >= 3.5 specific syntax "endless_methods_command_call.txt", + + # https://bugs.ruby-lang.org/issues/21168#note-5 + "command_method_call_2.txt", ] # These files contain code that is being parsed incorrectly by the parser diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 39325137ba07f2..4916ec8d9de752 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -33,6 +33,9 @@ class RipperTest < TestCase # https://bugs.ruby-lang.org/issues/17398#note-12 "endless_methods_command_call.txt", + + # https://bugs.ruby-lang.org/issues/21168#note-5 + "command_method_call_2.txt", ] # Skip these tests that we haven't implemented yet. diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb index b21ad81391ed1e..ec55e41967c6a0 100644 --- a/test/prism/ruby/ruby_parser_test.rb +++ b/test/prism/ruby/ruby_parser_test.rb @@ -79,6 +79,9 @@ class RubyParserTest < TestCase # Ruby >= 3.5 specific syntax "endless_methods_command_call.txt", + + # https://bugs.ruby-lang.org/issues/21168#note-5 + "command_method_call_2.txt", ] Fixture.each(except: failures) do |fixture| From d7c54df433c73f46b177dae594a001fc92fe5232 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 19 Sep 2025 13:42:36 -0400 Subject: [PATCH 08/22] [ruby/prism] Turn off failing test for parse.y https://github.com/ruby/prism/commit/cb27f5a70a --- test/prism/locals_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb index 950e7118af526a..0194bc6e5e3356 100644 --- a/test/prism/locals_test.rb +++ b/test/prism/locals_test.rb @@ -33,7 +33,8 @@ class LocalsTest < TestCase # Leaving these out until they are supported by parse.y. "leading_logical.txt", - "endless_methods_command_call.txt" + "endless_methods_command_call.txt", + "test_command_method_call_2.txt" ] Fixture.each(except: except) do |fixture| From 642188fb87a42c04d5672f4c9d16644d6cbcb207 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 19 Sep 2025 14:34:59 -0400 Subject: [PATCH 09/22] [ruby/prism] Fix up locals test skip name https://github.com/ruby/prism/commit/d1b22f59a0 --- test/prism/locals_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb index 0194bc6e5e3356..9a3224e8ef8843 100644 --- a/test/prism/locals_test.rb +++ b/test/prism/locals_test.rb @@ -34,7 +34,7 @@ class LocalsTest < TestCase # Leaving these out until they are supported by parse.y. "leading_logical.txt", "endless_methods_command_call.txt", - "test_command_method_call_2.txt" + "command_method_call_2.txt" ] Fixture.each(except: except) do |fixture| From 2ad3fbb9c79673bed3bad57c89f4a6fc3729c2b6 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Fri, 19 Sep 2025 19:52:34 +0100 Subject: [PATCH 10/22] ZJIT: Simplify NewHash HIR and Codegen We can use `Vec` instead of `Vec<(Opnd, Opnd)>` in NewHash HIR as it's the only usage of such type, which requires special handling. --- zjit/src/codegen.rs | 19 +++++-------------- zjit/src/hir.rs | 29 ++++++++++------------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index e0fd6cf2bd546e..7185c171c133d9 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -346,7 +346,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::Const { val: Const::Value(val) } => gen_const(*val), Insn::Const { .. } => panic!("Unexpected Const in gen_insn: {insn}"), Insn::NewArray { elements, state } => gen_new_array(asm, opnds!(elements), &function.frame_state(*state)), - Insn::NewHash { elements, state } => gen_new_hash(jit, asm, elements, &function.frame_state(*state)), + Insn::NewHash { elements, state } => gen_new_hash(jit, asm, opnds!(elements), &function.frame_state(*state)), Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)), Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)), @@ -1259,7 +1259,7 @@ fn gen_new_array( fn gen_new_hash( jit: &mut JITState, asm: &mut Assembler, - elements: &[(InsnId, InsnId)], + elements: Vec, state: &FrameState, ) -> lir::Opnd { gen_prepare_non_leaf_call(jit, asm, state); @@ -1268,19 +1268,10 @@ fn gen_new_hash( let new_hash = asm_ccall!(asm, rb_hash_new_with_size, lir::Opnd::Imm(cap)); if !elements.is_empty() { - let mut pairs = Vec::new(); - for (key_id, val_id) in elements.iter() { - let key = jit.get_opnd(*key_id); - let val = jit.get_opnd(*val_id); - pairs.push(key); - pairs.push(val); - } - - let argv = gen_push_opnds(jit, asm, &pairs); - let argc = (elements.len() * 2) as ::std::os::raw::c_long; - asm_ccall!(asm, rb_hash_bulk_insert, lir::Opnd::Imm(argc), argv, new_hash); + let argv = gen_push_opnds(jit, asm, &elements); + asm_ccall!(asm, rb_hash_bulk_insert, elements.len().into(), argv, new_hash); - gen_pop_opnds(asm, &pairs); + gen_pop_opnds(asm, &elements); } new_hash diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 08bdd5311f60a2..1cc029492953c3 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -549,7 +549,7 @@ pub enum Insn { ToNewArray { val: InsnId, state: InsnId }, NewArray { elements: Vec, state: InsnId }, /// NewHash contains a vec of (key, value) pairs - NewHash { elements: Vec<(InsnId,InsnId)>, state: InsnId }, + NewHash { elements: Vec, state: InsnId }, NewRange { low: InsnId, high: InsnId, flag: RangeType, state: InsnId }, NewRangeFixnum { low: InsnId, high: InsnId, flag: RangeType, state: InsnId }, ArrayDup { val: InsnId, state: InsnId }, @@ -816,9 +816,11 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::NewHash { elements, .. } => { write!(f, "NewHash")?; let mut prefix = " "; - for (key, value) in elements { - write!(f, "{prefix}{key}: {value}")?; - prefix = ", "; + for chunk in elements.chunks(2) { + if let [key, value] = chunk { + write!(f, "{prefix}{key}: {value}")?; + prefix = ", "; + } } Ok(()) } @@ -1462,13 +1464,7 @@ impl Function { &Defined { op_type, obj, pushval, v, state } => Defined { op_type, obj, pushval, v: find!(v), state: find!(state) }, &DefinedIvar { self_val, pushval, id, state } => DefinedIvar { self_val: find!(self_val), pushval, id, state }, &NewArray { ref elements, state } => NewArray { elements: find_vec!(elements), state: find!(state) }, - &NewHash { ref elements, state } => { - let mut found_elements = vec![]; - for &(key, value) in elements { - found_elements.push((find!(key), find!(value))); - } - NewHash { elements: found_elements, state: find!(state) } - } + &NewHash { ref elements, state } => NewHash { elements: find_vec!(elements), state: find!(state) }, &NewRange { low, high, flag, state } => NewRange { low: find!(low), high: find!(high), flag, state: find!(state) }, &NewRangeFixnum { low, high, flag, state } => NewRangeFixnum { low: find!(low), high: find!(high), flag, state: find!(state) }, &ArrayMax { ref elements, state } => ArrayMax { elements: find_vec!(elements), state: find!(state) }, @@ -2369,17 +2365,11 @@ impl Function { worklist.push_back(state); } &Insn::ArrayMax { ref elements, state } + | &Insn::NewHash { ref elements, state } | &Insn::NewArray { ref elements, state } => { worklist.extend(elements); worklist.push_back(state); } - &Insn::NewHash { ref elements, state } => { - for &(key, value) in elements { - worklist.push_back(key); - worklist.push_back(value); - } - worklist.push_back(state); - } &Insn::NewRange { low, high, state, .. } | &Insn::NewRangeFixnum { low, high, state, .. } => { worklist.push_back(low); @@ -3430,7 +3420,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { for _ in 0..(count/2) { let value = state.stack_pop()?; let key = state.stack_pop()?; - elements.push((key, value)); + elements.push(value); + elements.push(key); } elements.reverse(); state.stack_push(fun.push_insn(block, Insn::NewHash { elements, state: exit_id })); From f4482b047fa3facc78cf5d3439a70d0251862da3 Mon Sep 17 00:00:00 2001 From: Randy Stauner Date: Fri, 19 Sep 2025 15:00:27 -0700 Subject: [PATCH 11/22] Make it easier to reproduce commands from CI (#14609) * Comment on not auto-requesting reviews for workflow files * Make it easier to reproduce matrix test_task commands from CI Expand the interpolated command so that it is easier to see exactly what command was run. --- .github/auto_request_review.yml | 1 + .github/workflows/yjit-macos.yml | 1 + .github/workflows/yjit-ubuntu.yml | 1 + .github/workflows/zjit-macos.yml | 11 ++++++----- .github/workflows/zjit-ubuntu.yml | 11 ++++++----- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/auto_request_review.yml b/.github/auto_request_review.yml index c4c94681f0e387..51e0e4db973ca7 100644 --- a/.github/auto_request_review.yml +++ b/.github/auto_request_review.yml @@ -11,6 +11,7 @@ files: 'doc/zjit*': [team:jit] 'test/ruby/test_zjit*': [team:jit] 'defs/jit.mk': [team:jit] + # Skip github workflow files because the team don't necessarily need to review dependabot updates for GitHub Actions. It's noisy in notifications, and they're auto-merged anyway. options: ignore_draft: true # This currently doesn't work as intended. We want to skip reviews when only diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml index b44187b0fb1cd8..fc538fe51be876 100644 --- a/.github/workflows/yjit-macos.yml +++ b/.github/workflows/yjit-macos.yml @@ -145,6 +145,7 @@ jobs: test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}") + set -x make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \ RUN_OPTS="$RUN_OPTS" \ SPECOPTS="$SPECOPTS" diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index 1fac6e1d9395ae..e086582e2430b3 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -195,6 +195,7 @@ jobs: test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}") + set -x make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \ RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \ YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS" YJIT_BINDGEN_DIFF_OPTS="$YJIT_BINDGEN_DIFF_OPTS" diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 987a26a62bf6f0..b97f7b4118313f 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -112,11 +112,12 @@ jobs: echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV - name: make ${{ matrix.test_task }} - run: >- - make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} - RUN_OPTS="$RUN_OPTS" - SPECOPTS="$SPECOPTS" - TESTOPTS="$TESTOPTS" + run: | + set -x + make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \ + RUN_OPTS="$RUN_OPTS" \ + SPECOPTS="$SPECOPTS" \ + TESTOPTS="$TESTOPTS" timeout-minutes: 60 env: RUBY_TESTOPTS: '-q --tty=no' diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index c85a3799a006ca..50fea0287653f0 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -152,11 +152,12 @@ jobs: echo "RUBY_CRASH_REPORT=$(pwd)/rb_crash_%p.txt" >> $GITHUB_ENV - name: make ${{ matrix.test_task }} - run: >- - make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} - RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" - TESTOPTS="$TESTOPTS" - ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS" + run: | + set -x + make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \ + RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \ + TESTOPTS="$TESTOPTS" \ + ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS" timeout-minutes: 90 env: RUBY_TESTOPTS: '-q --tty=no' From e44bec9b92d7d6d7286f57637df6e785b12fafb1 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 19 Sep 2025 15:19:52 -0700 Subject: [PATCH 12/22] ZJIT: Fix disasm tests on release build (#14612) * ZJIT: Fix disasm tests on release build * Rename string() to hexdump() --- zjit/src/asm/arm64/mod.rs | 384 ++++++++-------- zjit/src/asm/mod.rs | 11 +- zjit/src/asm/x86_64/tests.rs | 806 ++++++++++++++++----------------- zjit/src/backend/arm64/mod.rs | 118 ++--- zjit/src/backend/x86_64/mod.rs | 198 ++++---- 5 files changed, 759 insertions(+), 758 deletions(-) diff --git a/zjit/src/asm/arm64/mod.rs b/zjit/src/asm/arm64/mod.rs index d7e48d6c0cf57e..176e51ee973e84 100644 --- a/zjit/src/asm/arm64/mod.rs +++ b/zjit/src/asm/arm64/mod.rs @@ -1246,129 +1246,129 @@ mod tests { #[test] fn test_add_reg() { let cb = compile(|cb| add(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, x2"); - assert_snapshot!(cb.string(), @"2000028b"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"2000028b"); } #[test] fn test_add_uimm() { let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c0091"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c0091"); } #[test] fn test_add_imm_positive() { let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c0091"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c0091"); } #[test] fn test_add_imm_negative() { let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(-7))); - assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00d1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00d1"); } #[test] fn test_adds_reg() { let cb = compile(|cb| adds(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, x2"); - assert_snapshot!(cb.string(), @"200002ab"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adds x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"200002ab"); } #[test] fn test_adds_uimm() { let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00b1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adds x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00b1"); } #[test] fn test_adds_imm_positive() { let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00b1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adds x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00b1"); } #[test] fn test_adds_imm_negative() { let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(-7))); - assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00f1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: subs x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00f1"); } #[test] fn test_adr() { let cb = compile(|cb| adr(cb, X10, A64Opnd::new_imm(20))); - assert_snapshot!(cb.disasm(), @" 0x0: adr x10, #0x14"); - assert_snapshot!(cb.string(), @"aa000010"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adr x10, #0x14")); + assert_snapshot!(cb.hexdump(), @"aa000010"); } #[test] fn test_adrp() { let cb = compile(|cb| adrp(cb, X10, A64Opnd::new_imm(0x8000))); - assert_snapshot!(cb.disasm(), @" 0x0: adrp x10, #0x8000"); - assert_snapshot!(cb.string(), @"4a000090"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adrp x10, #0x8000")); + assert_snapshot!(cb.hexdump(), @"4a000090"); } #[test] fn test_and_register() { let cb = compile(|cb| and(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, x2"); - assert_snapshot!(cb.string(), @"2000028a"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"2000028a"); } #[test] fn test_and_immediate() { let cb = compile(|cb| and(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, #7"); - assert_snapshot!(cb.string(), @"20084092"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"20084092"); } #[test] fn test_and_32b_immediate() { let cb = compile(|cb| and(cb, W0, W2, A64Opnd::new_uimm(0xfffff))); - assert_snapshot!(cb.disasm(), @" 0x0: and w0, w2, #0xfffff"); - assert_snapshot!(cb.string(), @"404c0012"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and w0, w2, #0xfffff")); + assert_snapshot!(cb.hexdump(), @"404c0012"); } #[test] fn test_ands_register() { let cb = compile(|cb| ands(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, x2"); - assert_snapshot!(cb.string(), @"200002ea"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ands x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"200002ea"); } #[test] fn test_ands_immediate() { let cb = compile(|cb| ands(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, #7"); - assert_snapshot!(cb.string(), @"200840f2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ands x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"200840f2"); } #[test] fn test_asr() { let cb = compile(|cb| asr(cb, X20, X21, A64Opnd::new_uimm(10))); - assert_snapshot!(cb.disasm(), @" 0x0: asr x20, x21, #0xa"); - assert_snapshot!(cb.string(), @"b4fe4a93"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: asr x20, x21, #0xa")); + assert_snapshot!(cb.hexdump(), @"b4fe4a93"); } #[test] fn test_bcond() { let offset = InstructionOffset::from_insns(0x100); let cb = compile(|cb| bcond(cb, Condition::NE, offset)); - assert_snapshot!(cb.disasm(), @" 0x0: b.ne #0x400"); - assert_snapshot!(cb.string(), @"01200054"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: b.ne #0x400")); + assert_snapshot!(cb.hexdump(), @"01200054"); } #[test] fn test_b() { let offset = InstructionOffset::from_insns((1 << 25) - 1); let cb = compile(|cb| b(cb, offset)); - assert_snapshot!(cb.disasm(), @" 0x0: b #0x7fffffc"); - assert_snapshot!(cb.string(), @"ffffff15"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: b #0x7fffffc")); + assert_snapshot!(cb.hexdump(), @"ffffff15"); } #[test] @@ -1391,8 +1391,8 @@ mod tests { fn test_bl() { let offset = InstructionOffset::from_insns(-(1 << 25)); let cb = compile(|cb| bl(cb, offset)); - assert_snapshot!(cb.disasm(), @" 0x0: bl #0xfffffffff8000000"); - assert_snapshot!(cb.string(), @"00000096"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: bl #0xfffffffff8000000")); + assert_snapshot!(cb.hexdump(), @"00000096"); } #[test] @@ -1414,15 +1414,15 @@ mod tests { #[test] fn test_blr() { let cb = compile(|cb| blr(cb, X20)); - assert_snapshot!(cb.disasm(), @" 0x0: blr x20"); - assert_snapshot!(cb.string(), @"80023fd6"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: blr x20")); + assert_snapshot!(cb.hexdump(), @"80023fd6"); } #[test] fn test_br() { let cb = compile(|cb| br(cb, X20)); - assert_snapshot!(cb.disasm(), @" 0x0: br x20"); - assert_snapshot!(cb.string(), @"80021fd6"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: br x20")); + assert_snapshot!(cb.hexdump(), @"80021fd6"); } #[test] @@ -1432,11 +1432,11 @@ mod tests { cbz(cb, X0, offset); cbz(cb, W0, offset); }); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: cbz x0, #0xfffffffffffffffc 0x4: cbz w0, #0 - "); - assert_snapshot!(cb.string(), @"e0ffffb4e0ffff34"); + ")); + assert_snapshot!(cb.hexdump(), @"e0ffffb4e0ffff34"); } #[test] @@ -1446,151 +1446,151 @@ mod tests { cbnz(cb, X20, offset); cbnz(cb, W20, offset); }); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: cbnz x20, #8 0x4: cbnz w20, #0xc - "); - assert_snapshot!(cb.string(), @"540000b554000035"); + ")); + assert_snapshot!(cb.hexdump(), @"540000b554000035"); } #[test] fn test_brk_none() { let cb = compile(|cb| brk(cb, A64Opnd::None)); - assert_snapshot!(cb.disasm(), @" 0x0: brk #0xf000"); - assert_snapshot!(cb.string(), @"00003ed4"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: brk #0xf000")); + assert_snapshot!(cb.hexdump(), @"00003ed4"); } #[test] fn test_brk_uimm() { let cb = compile(|cb| brk(cb, A64Opnd::new_uimm(14))); - assert_snapshot!(cb.disasm(), @" 0x0: brk #0xe"); - assert_snapshot!(cb.string(), @"c00120d4"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: brk #0xe")); + assert_snapshot!(cb.hexdump(), @"c00120d4"); } #[test] fn test_cmp_register() { let cb = compile(|cb| cmp(cb, X10, X11)); - assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, x11"); - assert_snapshot!(cb.string(), @"5f010beb"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp x10, x11")); + assert_snapshot!(cb.hexdump(), @"5f010beb"); } #[test] fn test_cmp_immediate() { let cb = compile(|cb| cmp(cb, X10, A64Opnd::new_uimm(14))); - assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, #0xe"); - assert_snapshot!(cb.string(), @"5f3900f1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp x10, #0xe")); + assert_snapshot!(cb.hexdump(), @"5f3900f1"); } #[test] fn test_csel() { let cb = compile(|cb| csel(cb, X10, X11, X12, Condition::EQ)); - assert_snapshot!(cb.disasm(), @" 0x0: csel x10, x11, x12, eq"); - assert_snapshot!(cb.string(), @"6a018c9a"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: csel x10, x11, x12, eq")); + assert_snapshot!(cb.hexdump(), @"6a018c9a"); } #[test] fn test_eor_register() { let cb = compile(|cb| eor(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, x12"); - assert_snapshot!(cb.string(), @"6a010cca"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: eor x10, x11, x12")); + assert_snapshot!(cb.hexdump(), @"6a010cca"); } #[test] fn test_eor_immediate() { let cb = compile(|cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, #7"); - assert_snapshot!(cb.string(), @"6a0940d2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: eor x10, x11, #7")); + assert_snapshot!(cb.hexdump(), @"6a0940d2"); } #[test] fn test_eor_32b_immediate() { let cb = compile(|cb| eor(cb, W9, W1, A64Opnd::new_uimm(0x80000001))); - assert_snapshot!(cb.disasm(), @" 0x0: eor w9, w1, #0x80000001"); - assert_snapshot!(cb.string(), @"29040152"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: eor w9, w1, #0x80000001")); + assert_snapshot!(cb.hexdump(), @"29040152"); } #[test] fn test_ldaddal() { let cb = compile(|cb| ldaddal(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: ldaddal x10, x11, [x12]"); - assert_snapshot!(cb.string(), @"8b01eaf8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldaddal x10, x11, [x12]")); + assert_snapshot!(cb.hexdump(), @"8b01eaf8"); } #[test] fn test_ldaxr() { let cb = compile(|cb| ldaxr(cb, X10, X11)); - assert_snapshot!(cb.disasm(), @" 0x0: ldaxr x10, [x11]"); - assert_snapshot!(cb.string(), @"6afd5fc8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldaxr x10, [x11]")); + assert_snapshot!(cb.hexdump(), @"6afd5fc8"); } #[test] fn test_ldp() { let cb = compile(|cb| ldp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]"); - assert_snapshot!(cb.string(), @"8a2d4da9"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldp x10, x11, [x12, #0xd0]")); + assert_snapshot!(cb.hexdump(), @"8a2d4da9"); } #[test] fn test_ldp_pre() { let cb = compile(|cb| ldp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]!"); - assert_snapshot!(cb.string(), @"8a2dcda9"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldp x10, x11, [x12, #0xd0]!")); + assert_snapshot!(cb.hexdump(), @"8a2dcda9"); } #[test] fn test_ldp_post() { let cb = compile(|cb| ldp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12], #0xd0"); - assert_snapshot!(cb.string(), @"8a2dcda8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldp x10, x11, [x12], #0xd0")); + assert_snapshot!(cb.hexdump(), @"8a2dcda8"); } #[test] fn test_ldr() { let cb = compile(|cb| ldr(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, x12]"); - assert_snapshot!(cb.string(), @"6a696cf8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldr x10, [x11, x12]")); + assert_snapshot!(cb.hexdump(), @"6a696cf8"); } #[test] fn test_ldr_literal() { let cb = compile(|cb| ldr_literal(cb, X0, 10.into())); - assert_snapshot!(cb.disasm(), @" 0x0: ldr x0, #0x28"); - assert_snapshot!(cb.string(), @"40010058"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldr x0, #0x28")); + assert_snapshot!(cb.hexdump(), @"40010058"); } #[test] fn test_ldr_post() { let cb = compile(|cb| ldr_post(cb, X10, A64Opnd::new_mem(64, X11, 16))); - assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11], #0x10"); - assert_snapshot!(cb.string(), @"6a0541f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldr x10, [x11], #0x10")); + assert_snapshot!(cb.hexdump(), @"6a0541f8"); } #[test] fn test_ldr_pre() { let cb = compile(|cb| ldr_pre(cb, X10, A64Opnd::new_mem(64, X11, 16))); - assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, #0x10]!"); - assert_snapshot!(cb.string(), @"6a0d41f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldr x10, [x11, #0x10]!")); + assert_snapshot!(cb.hexdump(), @"6a0d41f8"); } #[test] fn test_ldrh() { let cb = compile(|cb| ldrh(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]"); - assert_snapshot!(cb.string(), @"6a194079"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldrh w10, [x11, #0xc]")); + assert_snapshot!(cb.hexdump(), @"6a194079"); } #[test] fn test_ldrh_pre() { let cb = compile(|cb| ldrh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]!"); - assert_snapshot!(cb.string(), @"6acd4078"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldrh w10, [x11, #0xc]!")); + assert_snapshot!(cb.hexdump(), @"6acd4078"); } #[test] fn test_ldrh_post() { let cb = compile(|cb| ldrh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11], #0xc"); - assert_snapshot!(cb.string(), @"6ac54078"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldrh w10, [x11], #0xc")); + assert_snapshot!(cb.hexdump(), @"6ac54078"); } #[test] @@ -1599,353 +1599,353 @@ mod tests { ldurh(cb, W10, A64Opnd::new_mem(64, X1, 0)); ldurh(cb, W10, A64Opnd::new_mem(64, X1, 123)); }); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: ldurh w10, [x1] 0x4: ldurh w10, [x1, #0x7b] - "); - assert_snapshot!(cb.string(), @"2a0040782ab04778"); + ")); + assert_snapshot!(cb.hexdump(), @"2a0040782ab04778"); } #[test] fn test_ldur_memory() { let cb = compile(|cb| ldur(cb, X0, A64Opnd::new_mem(64, X1, 123))); - assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1, #0x7b]"); - assert_snapshot!(cb.string(), @"20b047f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldur x0, [x1, #0x7b]")); + assert_snapshot!(cb.hexdump(), @"20b047f8"); } #[test] fn test_ldur_register() { let cb = compile(|cb| ldur(cb, X0, X1)); - assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1]"); - assert_snapshot!(cb.string(), @"200040f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldur x0, [x1]")); + assert_snapshot!(cb.hexdump(), @"200040f8"); } #[test] fn test_ldursw() { let cb = compile(|cb| ldursw(cb, X10, A64Opnd::new_mem(64, X11, 123))); - assert_snapshot!(cb.disasm(), @" 0x0: ldursw x10, [x11, #0x7b]"); - assert_snapshot!(cb.string(), @"6ab187b8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldursw x10, [x11, #0x7b]")); + assert_snapshot!(cb.hexdump(), @"6ab187b8"); } #[test] fn test_lsl() { let cb = compile(|cb| lsl(cb, X10, X11, A64Opnd::new_uimm(14))); - assert_snapshot!(cb.disasm(), @" 0x0: lsl x10, x11, #0xe"); - assert_snapshot!(cb.string(), @"6ac572d3"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lsl x10, x11, #0xe")); + assert_snapshot!(cb.hexdump(), @"6ac572d3"); } #[test] fn test_lsr() { let cb = compile(|cb| lsr(cb, X10, X11, A64Opnd::new_uimm(14))); - assert_snapshot!(cb.disasm(), @" 0x0: lsr x10, x11, #0xe"); - assert_snapshot!(cb.string(), @"6afd4ed3"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lsr x10, x11, #0xe")); + assert_snapshot!(cb.hexdump(), @"6afd4ed3"); } #[test] fn test_mov_registers() { let cb = compile(|cb| mov(cb, X10, X11)); - assert_snapshot!(cb.disasm(), @" 0x0: mov x10, x11"); - assert_snapshot!(cb.string(), @"ea030baa"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x10, x11")); + assert_snapshot!(cb.hexdump(), @"ea030baa"); } #[test] fn test_mov_immediate() { let cb = compile(|cb| mov(cb, X10, A64Opnd::new_uimm(0x5555555555555555))); - assert_snapshot!(cb.disasm(), @" 0x0: orr x10, xzr, #0x5555555555555555"); - assert_snapshot!(cb.string(), @"eaf300b2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: orr x10, xzr, #0x5555555555555555")); + assert_snapshot!(cb.hexdump(), @"eaf300b2"); } #[test] fn test_mov_32b_immediate() { let cb = compile(|cb| mov(cb, W10, A64Opnd::new_uimm(0x80000001))); - assert_snapshot!(cb.disasm(), @" 0x0: mov w10, #-0x7fffffff"); - assert_snapshot!(cb.string(), @"ea070132"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov w10, #-0x7fffffff")); + assert_snapshot!(cb.hexdump(), @"ea070132"); } #[test] fn test_mov_into_sp() { let cb = compile(|cb| mov(cb, X31, X0)); - assert_snapshot!(cb.disasm(), @" 0x0: mov sp, x0"); - assert_snapshot!(cb.string(), @"1f000091"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov sp, x0")); + assert_snapshot!(cb.hexdump(), @"1f000091"); } #[test] fn test_mov_from_sp() { let cb = compile(|cb| mov(cb, X0, X31)); - assert_snapshot!(cb.disasm(), @" 0x0: mov x0, sp"); - assert_snapshot!(cb.string(), @"e0030091"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, sp")); + assert_snapshot!(cb.hexdump(), @"e0030091"); } #[test] fn test_movk() { let cb = compile(|cb| movk(cb, X0, A64Opnd::new_uimm(123), 16)); - assert_snapshot!(cb.disasm(), @" 0x0: movk x0, #0x7b, lsl #16"); - assert_snapshot!(cb.string(), @"600fa0f2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movk x0, #0x7b, lsl #16")); + assert_snapshot!(cb.hexdump(), @"600fa0f2"); } #[test] fn test_movn() { let cb = compile(|cb| movn(cb, X0, A64Opnd::new_uimm(123), 16)); - assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #-0x7b0001"); - assert_snapshot!(cb.string(), @"600fa092"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, #-0x7b0001")); + assert_snapshot!(cb.hexdump(), @"600fa092"); } #[test] fn test_movz() { let cb = compile(|cb| movz(cb, X0, A64Opnd::new_uimm(123), 16)); - assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #0x7b0000"); - assert_snapshot!(cb.string(), @"600fa0d2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, #0x7b0000")); + assert_snapshot!(cb.hexdump(), @"600fa0d2"); } #[test] fn test_mrs() { let cb = compile(|cb| mrs(cb, X10, SystemRegister::NZCV)); - assert_snapshot!(cb.disasm(), @" 0x0: mrs x10, nzcv"); - assert_snapshot!(cb.string(), @"0a423bd5"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mrs x10, nzcv")); + assert_snapshot!(cb.hexdump(), @"0a423bd5"); } #[test] fn test_msr() { let cb = compile(|cb| msr(cb, SystemRegister::NZCV, X10)); - assert_snapshot!(cb.disasm(), @" 0x0: msr nzcv, x10"); - assert_snapshot!(cb.string(), @"0a421bd5"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: msr nzcv, x10")); + assert_snapshot!(cb.hexdump(), @"0a421bd5"); } #[test] fn test_mul() { let cb = compile(|cb| mul(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: mul x10, x11, x12"); - assert_snapshot!(cb.string(), @"6a7d0c9b"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mul x10, x11, x12")); + assert_snapshot!(cb.hexdump(), @"6a7d0c9b"); } #[test] fn test_mvn() { let cb = compile(|cb| mvn(cb, X10, X11)); - assert_snapshot!(cb.disasm(), @" 0x0: mvn x10, x11"); - assert_snapshot!(cb.string(), @"ea032baa"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mvn x10, x11")); + assert_snapshot!(cb.hexdump(), @"ea032baa"); } #[test] fn test_nop() { let cb = compile(nop); - assert_snapshot!(cb.disasm(), @" 0x0: nop"); - assert_snapshot!(cb.string(), @"1f2003d5"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop")); + assert_snapshot!(cb.hexdump(), @"1f2003d5"); } #[test] fn test_orn() { let cb = compile(|cb| orn(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: orn x10, x11, x12"); - assert_snapshot!(cb.string(), @"6a012caa"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: orn x10, x11, x12")); + assert_snapshot!(cb.hexdump(), @"6a012caa"); } #[test] fn test_orr_register() { let cb = compile(|cb| orr(cb, X10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, x12"); - assert_snapshot!(cb.string(), @"6a010caa"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: orr x10, x11, x12")); + assert_snapshot!(cb.hexdump(), @"6a010caa"); } #[test] fn test_orr_immediate() { let cb = compile(|cb| orr(cb, X10, X11, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, #7"); - assert_snapshot!(cb.string(), @"6a0940b2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: orr x10, x11, #7")); + assert_snapshot!(cb.hexdump(), @"6a0940b2"); } #[test] fn test_orr_32b_immediate() { let cb = compile(|cb| orr(cb, W10, W11, A64Opnd::new_uimm(1))); - assert_snapshot!(cb.disasm(), @" 0x0: orr w10, w11, #1"); - assert_snapshot!(cb.string(), @"6a010032"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: orr w10, w11, #1")); + assert_snapshot!(cb.hexdump(), @"6a010032"); } #[test] fn test_ret_none() { let cb = compile(|cb| ret(cb, A64Opnd::None)); - assert_snapshot!(cb.disasm(), @" 0x0: ret"); - assert_snapshot!(cb.string(), @"c0035fd6"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ret")); + assert_snapshot!(cb.hexdump(), @"c0035fd6"); } #[test] fn test_ret_register() { let cb = compile(|cb| ret(cb, X20)); - assert_snapshot!(cb.disasm(), @" 0x0: ret x20"); - assert_snapshot!(cb.string(), @"80025fd6"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ret x20")); + assert_snapshot!(cb.hexdump(), @"80025fd6"); } #[test] fn test_stlxr() { let cb = compile(|cb| stlxr(cb, W10, X11, X12)); - assert_snapshot!(cb.disasm(), @" 0x0: stlxr w10, x11, [x12]"); - assert_snapshot!(cb.string(), @"8bfd0ac8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stlxr w10, x11, [x12]")); + assert_snapshot!(cb.hexdump(), @"8bfd0ac8"); } #[test] fn test_stp() { let cb = compile(|cb| stp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]"); - assert_snapshot!(cb.string(), @"8a2d0da9"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x10, x11, [x12, #0xd0]")); + assert_snapshot!(cb.hexdump(), @"8a2d0da9"); } #[test] fn test_stp_pre() { let cb = compile(|cb| stp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]!"); - assert_snapshot!(cb.string(), @"8a2d8da9"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x10, x11, [x12, #0xd0]!")); + assert_snapshot!(cb.hexdump(), @"8a2d8da9"); } #[test] fn test_stp_post() { let cb = compile(|cb| stp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); - assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12], #0xd0"); - assert_snapshot!(cb.string(), @"8a2d8da8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x10, x11, [x12], #0xd0")); + assert_snapshot!(cb.hexdump(), @"8a2d8da8"); } #[test] fn test_str_post() { let cb = compile(|cb| str_post(cb, X10, A64Opnd::new_mem(64, X11, -16))); - assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11], #0xfffffffffffffff0"); - assert_snapshot!(cb.string(), @"6a051ff8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: str x10, [x11], #0xfffffffffffffff0")); + assert_snapshot!(cb.hexdump(), @"6a051ff8"); } #[test] fn test_str_pre() { let cb = compile(|cb| str_pre(cb, X10, A64Opnd::new_mem(64, X11, -16))); - assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11, #-0x10]!"); - assert_snapshot!(cb.string(), @"6a0d1ff8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: str x10, [x11, #-0x10]!")); + assert_snapshot!(cb.hexdump(), @"6a0d1ff8"); } #[test] fn test_strh() { let cb = compile(|cb| strh(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]"); - assert_snapshot!(cb.string(), @"6a190079"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: strh w10, [x11, #0xc]")); + assert_snapshot!(cb.hexdump(), @"6a190079"); } #[test] fn test_strh_pre() { let cb = compile(|cb| strh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]!"); - assert_snapshot!(cb.string(), @"6acd0078"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: strh w10, [x11, #0xc]!")); + assert_snapshot!(cb.hexdump(), @"6acd0078"); } #[test] fn test_strh_post() { let cb = compile(|cb| strh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); - assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11], #0xc"); - assert_snapshot!(cb.string(), @"6ac50078"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: strh w10, [x11], #0xc")); + assert_snapshot!(cb.hexdump(), @"6ac50078"); } #[test] fn test_stur_64_bits() { let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(64, X11, 128))); - assert_snapshot!(cb.disasm(), @" 0x0: stur x10, [x11, #0x80]"); - assert_snapshot!(cb.string(), @"6a0108f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stur x10, [x11, #0x80]")); + assert_snapshot!(cb.hexdump(), @"6a0108f8"); } #[test] fn test_stur_32_bits() { let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(32, X11, 128))); - assert_snapshot!(cb.disasm(), @" 0x0: stur w10, [x11, #0x80]"); - assert_snapshot!(cb.string(), @"6a0108b8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stur w10, [x11, #0x80]")); + assert_snapshot!(cb.hexdump(), @"6a0108b8"); } #[test] fn test_sub_reg() { let cb = compile(|cb| sub(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, x2"); - assert_snapshot!(cb.string(), @"200002cb"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"200002cb"); } #[test] fn test_sub_uimm() { let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00d1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00d1"); } #[test] fn test_sub_imm_positive() { let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00d1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00d1"); } #[test] fn test_sub_imm_negative() { let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(-7))); - assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c0091"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c0091"); } #[test] fn test_subs_reg() { let cb = compile(|cb| subs(cb, X0, X1, X2)); - assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, x2"); - assert_snapshot!(cb.string(), @"200002eb"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: subs x0, x1, x2")); + assert_snapshot!(cb.hexdump(), @"200002eb"); } #[test] fn test_subs_imm_positive() { let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00f1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: subs x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00f1"); } #[test] fn test_subs_imm_negative() { let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(-7))); - assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00b1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adds x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00b1"); } #[test] fn test_subs_uimm() { let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); - assert_snapshot!(cb.string(), @"201c00f1"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: subs x0, x1, #7")); + assert_snapshot!(cb.hexdump(), @"201c00f1"); } #[test] fn test_sxtw() { let cb = compile(|cb| sxtw(cb, X10, W11)); - assert_snapshot!(cb.disasm(), @" 0x0: sxtw x10, w11"); - assert_snapshot!(cb.string(), @"6a7d4093"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sxtw x10, w11")); + assert_snapshot!(cb.hexdump(), @"6a7d4093"); } #[test] fn test_tbnz() { let cb = compile(|cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); - assert_snapshot!(cb.disasm(), @" 0x0: tbnz w10, #0xa, #8"); - assert_snapshot!(cb.string(), @"4a005037"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: tbnz w10, #0xa, #8")); + assert_snapshot!(cb.hexdump(), @"4a005037"); } #[test] fn test_tbz() { let cb = compile(|cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); - assert_snapshot!(cb.disasm(), @" 0x0: tbz w10, #0xa, #8"); - assert_snapshot!(cb.string(), @"4a005036"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: tbz w10, #0xa, #8")); + assert_snapshot!(cb.hexdump(), @"4a005036"); } #[test] fn test_tst_register() { let cb = compile(|cb| tst(cb, X0, X1)); - assert_snapshot!(cb.disasm(), @" 0x0: tst x0, x1"); - assert_snapshot!(cb.string(), @"1f0001ea"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: tst x0, x1")); + assert_snapshot!(cb.hexdump(), @"1f0001ea"); } #[test] fn test_tst_immediate() { let cb = compile(|cb| tst(cb, X1, A64Opnd::new_uimm(7))); - assert_snapshot!(cb.disasm(), @" 0x0: tst x1, #7"); - assert_snapshot!(cb.string(), @"3f0840f2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: tst x1, #7")); + assert_snapshot!(cb.hexdump(), @"3f0840f2"); } #[test] fn test_tst_32b_immediate() { let cb = compile(|cb| tst(cb, W0, A64Opnd::new_uimm(0xffff))); - assert_snapshot!(cb.disasm(), @" 0x0: tst w0, #0xffff"); - assert_snapshot!(cb.string(), @"1f3c0072"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: tst w0, #0xffff")); + assert_snapshot!(cb.hexdump(), @"1f3c0072"); } #[test] @@ -1956,11 +1956,11 @@ mod tests { add_extended(&mut cb, X30, X30, X30); add_extended(&mut cb, X31, X31, X31); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add x10, x11, x9, uxtx 0x4: add x30, x30, x30, uxtx 0x8: add sp, sp, xzr - "); - assert_snapshot!(cb.string(), @"6a61298bde633e8bff633f8b"); + ")); + assert_snapshot!(cb.hexdump(), @"6a61298bde633e8bff633f8b"); } } diff --git a/zjit/src/asm/mod.rs b/zjit/src/asm/mod.rs index d866515c82373a..2ac864047cabb5 100644 --- a/zjit/src/asm/mod.rs +++ b/zjit/src/asm/mod.rs @@ -282,22 +282,21 @@ impl CodeBlock { self.mem_block.borrow_mut().mark_all_executable(); } - /// Return the disasm of generated code for testing + /// Call a func with the disasm of generated code for testing + #[allow(unused_variables)] #[cfg(test)] - pub fn disasm(&self) -> String { + pub fn with_disasm(&self, func: T) where T: Fn(String) { #[cfg(feature = "disasm")] { let start_addr = self.get_ptr(0).raw_addr(self); let end_addr = self.get_write_ptr().raw_addr(self); - crate::disasm::disasm_addr_range(self, start_addr, end_addr) + func(crate::disasm::disasm_addr_range(self, start_addr, end_addr)); } - #[cfg(not(feature = "disasm"))] - unreachable!("zjit-test should enable disasm feature") } /// Return the hex dump of generated code for testing #[cfg(test)] - pub fn string(&self) -> String { + pub fn hexdump(&self) -> String { format!("{:x}", self) } } diff --git a/zjit/src/asm/x86_64/tests.rs b/zjit/src/asm/x86_64/tests.rs index aa8d31b215b6c7..a095d73f89faa1 100644 --- a/zjit/src/asm/x86_64/tests.rs +++ b/zjit/src/asm/x86_64/tests.rs @@ -36,39 +36,39 @@ fn test_add() { let cb15 = compile(|cb| add(cb, ECX, imm_opnd(8))); let cb16 = compile(|cb| add(cb, ECX, imm_opnd(255))); - assert_snapshot!(cb01.disasm(), @" 0x0: add cl, 3"); - assert_snapshot!(cb02.disasm(), @" 0x0: add cl, bl"); - assert_snapshot!(cb03.disasm(), @" 0x0: add cl, spl"); - assert_snapshot!(cb04.disasm(), @" 0x0: add cx, bx"); - assert_snapshot!(cb05.disasm(), @" 0x0: add rax, rbx"); - assert_snapshot!(cb06.disasm(), @" 0x0: add ecx, edx"); - assert_snapshot!(cb07.disasm(), @" 0x0: add rdx, r14"); - assert_snapshot!(cb08.disasm(), @" 0x0: add qword ptr [rax], rdx"); - assert_snapshot!(cb09.disasm(), @" 0x0: add rdx, qword ptr [rax]"); - assert_snapshot!(cb10.disasm(), @" 0x0: add rdx, qword ptr [rax + 8]"); - assert_snapshot!(cb11.disasm(), @" 0x0: add rdx, qword ptr [rax + 0xff]"); - assert_snapshot!(cb12.disasm(), @" 0x0: add qword ptr [rax + 0x7f], 0xff"); - assert_snapshot!(cb13.disasm(), @" 0x0: add dword ptr [rax], edx"); - assert_snapshot!(cb14.disasm(), @" 0x0: add rsp, 8"); - assert_snapshot!(cb15.disasm(), @" 0x0: add ecx, 8"); - assert_snapshot!(cb16.disasm(), @" 0x0: add ecx, 0xff"); - - assert_snapshot!(cb01.string(), @"80c103"); - assert_snapshot!(cb02.string(), @"00d9"); - assert_snapshot!(cb03.string(), @"4000e1"); - assert_snapshot!(cb04.string(), @"6601d9"); - assert_snapshot!(cb05.string(), @"4801d8"); - assert_snapshot!(cb06.string(), @"01d1"); - assert_snapshot!(cb07.string(), @"4c01f2"); - assert_snapshot!(cb08.string(), @"480110"); - assert_snapshot!(cb09.string(), @"480310"); - assert_snapshot!(cb10.string(), @"48035008"); - assert_snapshot!(cb11.string(), @"480390ff000000"); - assert_snapshot!(cb12.string(), @"4881407fff000000"); - assert_snapshot!(cb13.string(), @"0110"); - assert_snapshot!(cb14.string(), @"4883c408"); - assert_snapshot!(cb15.string(), @"83c108"); - assert_snapshot!(cb16.string(), @"81c1ff000000"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add cl, 3")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add cl, bl")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add cl, spl")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add cx, bx")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rax, rbx")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add ecx, edx")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rdx, r14")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add qword ptr [rax], rdx")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rdx, qword ptr [rax]")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rdx, qword ptr [rax + 8]")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rdx, qword ptr [rax + 0xff]")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add qword ptr [rax + 0x7f], 0xff")); + cb13.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add dword ptr [rax], edx")); + cb14.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add rsp, 8")); + cb15.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add ecx, 8")); + cb16.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add ecx, 0xff")); + + assert_snapshot!(cb01.hexdump(), @"80c103"); + assert_snapshot!(cb02.hexdump(), @"00d9"); + assert_snapshot!(cb03.hexdump(), @"4000e1"); + assert_snapshot!(cb04.hexdump(), @"6601d9"); + assert_snapshot!(cb05.hexdump(), @"4801d8"); + assert_snapshot!(cb06.hexdump(), @"01d1"); + assert_snapshot!(cb07.hexdump(), @"4c01f2"); + assert_snapshot!(cb08.hexdump(), @"480110"); + assert_snapshot!(cb09.hexdump(), @"480310"); + assert_snapshot!(cb10.hexdump(), @"48035008"); + assert_snapshot!(cb11.hexdump(), @"480390ff000000"); + assert_snapshot!(cb12.hexdump(), @"4881407fff000000"); + assert_snapshot!(cb13.hexdump(), @"0110"); + assert_snapshot!(cb14.hexdump(), @"4883c408"); + assert_snapshot!(cb15.hexdump(), @"83c108"); + assert_snapshot!(cb16.hexdump(), @"81c1ff000000"); } #[test] @@ -86,23 +86,23 @@ fn test_add_unsigned() { let cb7 = compile(|cb| add(cb, R8, uimm_opnd(1))); let cb8 = compile(|cb| add(cb, R8, uimm_opnd(i32::MAX.try_into().unwrap()))); - assert_snapshot!(cb1.disasm(), @" 0x0: add r8b, 1"); - assert_snapshot!(cb2.disasm(), @" 0x0: add r8b, 0x7f"); - assert_snapshot!(cb3.disasm(), @" 0x0: add r8w, 1"); - assert_snapshot!(cb4.disasm(), @" 0x0: add r8w, 0x7fff"); - assert_snapshot!(cb5.disasm(), @" 0x0: add r8d, 1"); - assert_snapshot!(cb6.disasm(), @" 0x0: add r8d, 0x7fffffff"); - assert_snapshot!(cb7.disasm(), @" 0x0: add r8, 1"); - assert_snapshot!(cb8.disasm(), @" 0x0: add r8, 0x7fffffff"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8b, 1")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8b, 0x7f")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8w, 1")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8w, 0x7fff")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8d, 1")); + cb6.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8d, 0x7fffffff")); + cb7.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8, 1")); + cb8.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r8, 0x7fffffff")); - assert_snapshot!(cb1.string(), @"4180c001"); - assert_snapshot!(cb2.string(), @"4180c07f"); - assert_snapshot!(cb3.string(), @"664183c001"); - assert_snapshot!(cb4.string(), @"664181c0ff7f"); - assert_snapshot!(cb5.string(), @"4183c001"); - assert_snapshot!(cb6.string(), @"4181c0ffffff7f"); - assert_snapshot!(cb7.string(), @"4983c001"); - assert_snapshot!(cb8.string(), @"4981c0ffffff7f"); + assert_snapshot!(cb1.hexdump(), @"4180c001"); + assert_snapshot!(cb2.hexdump(), @"4180c07f"); + assert_snapshot!(cb3.hexdump(), @"664183c001"); + assert_snapshot!(cb4.hexdump(), @"664181c0ff7f"); + assert_snapshot!(cb5.hexdump(), @"4183c001"); + assert_snapshot!(cb6.hexdump(), @"4181c0ffffff7f"); + assert_snapshot!(cb7.hexdump(), @"4983c001"); + assert_snapshot!(cb8.hexdump(), @"4981c0ffffff7f"); } #[test] @@ -110,11 +110,11 @@ fn test_and() { let cb1 = compile(|cb| and(cb, EBP, R12D)); let cb2 = compile(|cb| and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08))); - assert_snapshot!(cb1.disasm(), @" 0x0: and ebp, r12d"); - assert_snapshot!(cb2.disasm(), @" 0x0: and qword ptr [rax], 8"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and ebp, r12d")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and qword ptr [rax], 8")); - assert_snapshot!(cb1.string(), @"4421e5"); - assert_snapshot!(cb2.string(), @"48832008"); + assert_snapshot!(cb1.hexdump(), @"4421e5"); + assert_snapshot!(cb2.hexdump(), @"48832008"); } #[test] @@ -124,8 +124,8 @@ fn test_call_label() { call_label(cb, label_idx); cb.link_labels(); }); - assert_snapshot!(cb.disasm(), @" 0x0: call 0"); - assert_snapshot!(cb.string(), @"e8fbffffff"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: call 0")); + assert_snapshot!(cb.hexdump(), @"e8fbffffff"); } #[test] @@ -135,22 +135,22 @@ fn test_call_ptr() { let ptr = cb.get_write_ptr(); call_ptr(cb, RAX, ptr.raw_ptr(cb)); }); - assert_snapshot!(cb.disasm(), @" 0x0: call 0"); - assert_snapshot!(cb.string(), @"e8fbffffff"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: call 0")); + assert_snapshot!(cb.hexdump(), @"e8fbffffff"); } #[test] fn test_call_reg() { let cb = compile(|cb| call(cb, RAX)); - assert_snapshot!(cb.disasm(), @" 0x0: call rax"); - assert_snapshot!(cb.string(), @"ffd0"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: call rax")); + assert_snapshot!(cb.hexdump(), @"ffd0"); } #[test] fn test_call_mem() { let cb = compile(|cb| call(cb, mem_opnd(64, RSP, 8))); - assert_snapshot!(cb.disasm(), @" 0x0: call qword ptr [rsp + 8]"); - assert_snapshot!(cb.string(), @"ff542408"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: call qword ptr [rsp + 8]")); + assert_snapshot!(cb.hexdump(), @"ff542408"); } #[test] @@ -161,17 +161,17 @@ fn test_cmovcc() { let cb4 = compile(|cb| cmovl(cb, RBX, RBP)); let cb5 = compile(|cb| cmovle(cb, ESI, mem_opnd(32, RSP, 4))); - assert_snapshot!(cb1.disasm(), @" 0x0: cmovg esi, edi"); - assert_snapshot!(cb2.disasm(), @" 0x0: cmovg esi, dword ptr [rbp + 0xc]"); - assert_snapshot!(cb3.disasm(), @" 0x0: cmovl eax, ecx"); - assert_snapshot!(cb4.disasm(), @" 0x0: cmovl rbx, rbp"); - assert_snapshot!(cb5.disasm(), @" 0x0: cmovle esi, dword ptr [rsp + 4]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmovg esi, edi")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmovg esi, dword ptr [rbp + 0xc]")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmovl eax, ecx")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmovl rbx, rbp")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmovle esi, dword ptr [rsp + 4]")); - assert_snapshot!(cb1.string(), @"0f4ff7"); - assert_snapshot!(cb2.string(), @"0f4f750c"); - assert_snapshot!(cb3.string(), @"0f4cc1"); - assert_snapshot!(cb4.string(), @"480f4cdd"); - assert_snapshot!(cb5.string(), @"0f4e742404"); + assert_snapshot!(cb1.hexdump(), @"0f4ff7"); + assert_snapshot!(cb2.hexdump(), @"0f4f750c"); + assert_snapshot!(cb3.hexdump(), @"0f4cc1"); + assert_snapshot!(cb4.hexdump(), @"480f4cdd"); + assert_snapshot!(cb5.hexdump(), @"0f4e742404"); } #[test] @@ -182,24 +182,24 @@ fn test_cmp() { let cb4 = compile(|cb| cmp(cb, RAX, imm_opnd(2))); let cb5 = compile(|cb| cmp(cb, ECX, uimm_opnd(0x8000_0000))); - assert_snapshot!(cb1.disasm(), @" 0x0: cmp cl, dl"); - assert_snapshot!(cb2.disasm(), @" 0x0: cmp ecx, edi"); - assert_snapshot!(cb3.disasm(), @" 0x0: cmp rdx, qword ptr [r12]"); - assert_snapshot!(cb4.disasm(), @" 0x0: cmp rax, 2"); - assert_snapshot!(cb5.disasm(), @" 0x0: cmp ecx, 0x80000000"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp cl, dl")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp ecx, edi")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp rdx, qword ptr [r12]")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp rax, 2")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp ecx, 0x80000000")); - assert_snapshot!(cb1.string(), @"38d1"); - assert_snapshot!(cb2.string(), @"39f9"); - assert_snapshot!(cb3.string(), @"493b1424"); - assert_snapshot!(cb4.string(), @"4883f802"); - assert_snapshot!(cb5.string(), @"81f900000080"); + assert_snapshot!(cb1.hexdump(), @"38d1"); + assert_snapshot!(cb2.hexdump(), @"39f9"); + assert_snapshot!(cb3.hexdump(), @"493b1424"); + assert_snapshot!(cb4.hexdump(), @"4883f802"); + assert_snapshot!(cb5.hexdump(), @"81f900000080"); } #[test] fn test_cqo() { let cb = compile(cqo); - assert_snapshot!(cb.disasm(), @" 0x0: cqo"); - assert_snapshot!(cb.string(), @"4899"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cqo")); + assert_snapshot!(cb.hexdump(), @"4899"); } #[test] @@ -209,13 +209,13 @@ fn test_imul() { // Operands flipped for encoding since multiplication is commutative let cb3 = compile(|cb| imul(cb, mem_opnd(64, RAX, 0), RDX)); - assert_snapshot!(cb1.disasm(), @" 0x0: imul rax, rbx"); - assert_snapshot!(cb2.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); - assert_snapshot!(cb3.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: imul rax, rbx")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: imul rdx, qword ptr [rax]")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: imul rdx, qword ptr [rax]")); - assert_snapshot!(cb1.string(), @"480fafc3"); - assert_snapshot!(cb2.string(), @"480faf10"); - assert_snapshot!(cb3.string(), @"480faf10"); + assert_snapshot!(cb1.hexdump(), @"480fafc3"); + assert_snapshot!(cb2.hexdump(), @"480faf10"); + assert_snapshot!(cb3.hexdump(), @"480faf10"); } #[test] @@ -225,8 +225,8 @@ fn test_jge_label() { jge_label(cb, label_idx); cb.link_labels(); }); - assert_snapshot!(cb.disasm(), @" 0x0: jge 0"); - assert_snapshot!(cb.string(), @"0f8dfaffffff"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: jge 0")); + assert_snapshot!(cb.hexdump(), @"0f8dfaffffff"); } #[test] @@ -246,18 +246,18 @@ fn test_jmp_label() { cb.link_labels(); }); - assert_snapshot!(cb1.disasm(), @" 0x0: jmp 5"); - assert_snapshot!(cb2.disasm(), @" 0x0: jmp 0"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: jmp 5")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: jmp 0")); - assert_snapshot!(cb1.string(), @"e900000000"); - assert_snapshot!(cb2.string(), @"e9fbffffff"); + assert_snapshot!(cb1.hexdump(), @"e900000000"); + assert_snapshot!(cb2.hexdump(), @"e9fbffffff"); } #[test] fn test_jmp_rm() { let cb = compile(|cb| jmp_rm(cb, R12)); - assert_snapshot!(cb.disasm(), @" 0x0: jmp r12"); - assert_snapshot!(cb.string(), @"41ffe4"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: jmp r12")); + assert_snapshot!(cb.hexdump(), @"41ffe4"); } #[test] @@ -267,8 +267,8 @@ fn test_jo_label() { jo_label(cb, label_idx); cb.link_labels(); }); - assert_snapshot!(cb.disasm(), @" 0x0: jo 0"); - assert_snapshot!(cb.string(), @"0f80faffffff"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: jo 0")); + assert_snapshot!(cb.hexdump(), @"0f80faffffff"); } #[test] @@ -278,15 +278,15 @@ fn test_lea() { let cb3 = compile(|cb| lea(cb, RAX, mem_opnd(8, RIP, 5))); let cb4 = compile(|cb| lea(cb, RDI, mem_opnd(8, RIP, 5))); - assert_snapshot!(cb1.disasm(), @" 0x0: lea rdx, [rcx + 8]"); - assert_snapshot!(cb2.disasm(), @" 0x0: lea rax, [rip]"); - assert_snapshot!(cb3.disasm(), @" 0x0: lea rax, [rip + 5]"); - assert_snapshot!(cb4.disasm(), @" 0x0: lea rdi, [rip + 5]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lea rdx, [rcx + 8]")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lea rax, [rip]")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lea rax, [rip + 5]")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lea rdi, [rip + 5]")); - assert_snapshot!(cb1.string(), @"488d5108"); - assert_snapshot!(cb2.string(), @"488d0500000000"); - assert_snapshot!(cb3.string(), @"488d0505000000"); - assert_snapshot!(cb4.string(), @"488d3d05000000"); + assert_snapshot!(cb1.hexdump(), @"488d5108"); + assert_snapshot!(cb2.hexdump(), @"488d0500000000"); + assert_snapshot!(cb3.hexdump(), @"488d0505000000"); + assert_snapshot!(cb4.hexdump(), @"488d3d05000000"); } #[test] @@ -320,59 +320,59 @@ fn test_mov() { let cb25 = compile(|cb| mov(cb, mem_opnd(64, R11, 0), R10)); let cb26 = compile(|cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12))); - assert_snapshot!(cb01.disasm(), @" 0x0: mov eax, 7"); - assert_snapshot!(cb02.disasm(), @" 0x0: mov eax, 0xfffffffd"); - assert_snapshot!(cb03.disasm(), @" 0x0: mov r15d, 3"); - assert_snapshot!(cb04.disasm(), @" 0x0: mov eax, ebx"); - assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, ecx"); - assert_snapshot!(cb06.disasm(), @" 0x0: mov edx, dword ptr [rbx + 0x80]"); - assert_snapshot!(cb07.disasm(), @" 0x0: mov rax, qword ptr [rsp + 4]"); - assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0x34"); - assert_snapshot!(cb09.disasm(), @" 0x0: movabs r8, 0x80000000"); - assert_snapshot!(cb10.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); - assert_snapshot!(cb11.disasm(), @" 0x0: mov eax, 0x34"); - assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffc0000000000002"); - assert_snapshot!(cb13.disasm(), @" 0x0: movabs rax, 0x80000000"); - assert_snapshot!(cb14.disasm(), @" 0x0: movabs rax, 0xffffffffffffffcc"); - assert_snapshot!(cb15.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); - assert_snapshot!(cb16.disasm(), @" 0x0: mov cl, r9b"); - assert_snapshot!(cb17.disasm(), @" 0x0: mov rbx, rax"); - assert_snapshot!(cb18.disasm(), @" 0x0: mov rdi, rbx"); - assert_snapshot!(cb19.disasm(), @" 0x0: mov sil, 0xb"); - assert_snapshot!(cb20.disasm(), @" 0x0: mov byte ptr [rsp], 0xfd"); - assert_snapshot!(cb21.disasm(), @" 0x0: mov qword ptr [rdi + 8], 1"); - assert_snapshot!(cb22.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x11"); - assert_snapshot!(cb23.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x80000001"); - assert_snapshot!(cb24.disasm(), @" 0x0: mov dword ptr [r8 + 0x14], ebx"); - assert_snapshot!(cb25.disasm(), @" 0x0: mov qword ptr [r11], r10"); - assert_snapshot!(cb26.disasm(), @" 0x0: mov qword ptr [rdx - 8], 0xfffffffffffffff4"); - - assert_snapshot!(cb01.string(), @"b807000000"); - assert_snapshot!(cb02.string(), @"b8fdffffff"); - assert_snapshot!(cb03.string(), @"41bf03000000"); - assert_snapshot!(cb04.string(), @"89d8"); - assert_snapshot!(cb05.string(), @"89c8"); - assert_snapshot!(cb06.string(), @"8b9380000000"); - assert_snapshot!(cb07.string(), @"488b442404"); - assert_snapshot!(cb08.string(), @"41b834000000"); - assert_snapshot!(cb09.string(), @"49b80000008000000000"); - assert_snapshot!(cb10.string(), @"49b8ffffffffffffffff"); - assert_snapshot!(cb11.string(), @"b834000000"); - assert_snapshot!(cb12.string(), @"48b8020000000000c0ff"); - assert_snapshot!(cb13.string(), @"48b80000008000000000"); - assert_snapshot!(cb14.string(), @"48b8ccffffffffffffff"); - assert_snapshot!(cb15.string(), @"48b8ffffffffffffffff"); - assert_snapshot!(cb16.string(), @"4488c9"); - assert_snapshot!(cb17.string(), @"4889c3"); - assert_snapshot!(cb18.string(), @"4889df"); - assert_snapshot!(cb19.string(), @"40b60b"); - assert_snapshot!(cb20.string(), @"c60424fd"); - assert_snapshot!(cb21.string(), @"48c7470801000000"); - assert_snapshot!(cb22.string(), @"c7400411000000"); - assert_snapshot!(cb23.string(), @"c7400401000080"); - assert_snapshot!(cb24.string(), @"41895814"); - assert_snapshot!(cb25.string(), @"4d8913"); - assert_snapshot!(cb26.string(), @"48c742f8f4ffffff"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 7")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 0xfffffffd")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r15d, 3")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, ebx")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, ecx")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov edx, dword ptr [rbx + 0x80]")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rax, qword ptr [rsp + 4]")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 0x34")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0x80000000")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0xffffffffffffffff")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 0x34")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0xffc0000000000002")); + cb13.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0x80000000")); + cb14.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0xffffffffffffffcc")); + cb15.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0xffffffffffffffff")); + cb16.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov cl, r9b")); + cb17.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rbx, rax")); + cb18.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rdi, rbx")); + cb19.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov sil, 0xb")); + cb20.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov byte ptr [rsp], 0xfd")); + cb21.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov qword ptr [rdi + 8], 1")); + cb22.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov dword ptr [rax + 4], 0x11")); + cb23.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov dword ptr [rax + 4], 0x80000001")); + cb24.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov dword ptr [r8 + 0x14], ebx")); + cb25.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov qword ptr [r11], r10")); + cb26.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov qword ptr [rdx - 8], 0xfffffffffffffff4")); + + assert_snapshot!(cb01.hexdump(), @"b807000000"); + assert_snapshot!(cb02.hexdump(), @"b8fdffffff"); + assert_snapshot!(cb03.hexdump(), @"41bf03000000"); + assert_snapshot!(cb04.hexdump(), @"89d8"); + assert_snapshot!(cb05.hexdump(), @"89c8"); + assert_snapshot!(cb06.hexdump(), @"8b9380000000"); + assert_snapshot!(cb07.hexdump(), @"488b442404"); + assert_snapshot!(cb08.hexdump(), @"41b834000000"); + assert_snapshot!(cb09.hexdump(), @"49b80000008000000000"); + assert_snapshot!(cb10.hexdump(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb11.hexdump(), @"b834000000"); + assert_snapshot!(cb12.hexdump(), @"48b8020000000000c0ff"); + assert_snapshot!(cb13.hexdump(), @"48b80000008000000000"); + assert_snapshot!(cb14.hexdump(), @"48b8ccffffffffffffff"); + assert_snapshot!(cb15.hexdump(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb16.hexdump(), @"4488c9"); + assert_snapshot!(cb17.hexdump(), @"4889c3"); + assert_snapshot!(cb18.hexdump(), @"4889df"); + assert_snapshot!(cb19.hexdump(), @"40b60b"); + assert_snapshot!(cb20.hexdump(), @"c60424fd"); + assert_snapshot!(cb21.hexdump(), @"48c7470801000000"); + assert_snapshot!(cb22.hexdump(), @"c7400411000000"); + assert_snapshot!(cb23.hexdump(), @"c7400401000080"); + assert_snapshot!(cb24.hexdump(), @"41895814"); + assert_snapshot!(cb25.hexdump(), @"4d8913"); + assert_snapshot!(cb26.hexdump(), @"48c742f8f4ffffff"); } #[test] @@ -380,11 +380,11 @@ fn test_movabs() { let cb1 = compile(|cb| movabs(cb, R8, 0x34)); let cb2 = compile(|cb| movabs(cb, R8, 0x80000000)); - assert_snapshot!(cb1.disasm(), @" 0x0: movabs r8, 0x34"); - assert_snapshot!(cb2.disasm(), @" 0x0: movabs r8, 0x80000000"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0x34")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0x80000000")); - assert_snapshot!(cb1.string(), @"49b83400000000000000"); - assert_snapshot!(cb2.string(), @"49b80000008000000000"); + assert_snapshot!(cb1.hexdump(), @"49b83400000000000000"); + assert_snapshot!(cb2.hexdump(), @"49b80000008000000000"); } #[test] @@ -421,49 +421,49 @@ fn test_mov_unsigned() { // MOV r64, imm64, will not move down into 32 bit since it does not fit into 32 bits let cb21 = compile(|cb| mov(cb, R8, uimm_opnd(u64::MAX))); - assert_snapshot!(cb01.disasm(), @" 0x0: mov al, 1"); - assert_snapshot!(cb02.disasm(), @" 0x0: mov al, 0xff"); - assert_snapshot!(cb03.disasm(), @" 0x0: mov ax, 1"); - assert_snapshot!(cb04.disasm(), @" 0x0: mov ax, 0xffff"); - assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, 1"); - assert_snapshot!(cb06.disasm(), @" 0x0: mov eax, 0xffffffff"); - assert_snapshot!(cb07.disasm(), @" 0x0: mov r8d, 0"); - assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0xffffffff"); - assert_snapshot!(cb09.disasm(), @" 0x0: mov eax, 1"); - assert_snapshot!(cb10.disasm(), @" 0x0: mov eax, 0xffffffff"); - assert_snapshot!(cb11.disasm(), @" 0x0: movabs rax, 0x100000000"); - assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); - assert_snapshot!(cb13.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); - assert_snapshot!(cb14.disasm(), @" 0x0: mov r8b, 1"); - assert_snapshot!(cb15.disasm(), @" 0x0: mov r8b, 0xff"); - assert_snapshot!(cb16.disasm(), @" 0x0: mov r8w, 1"); - assert_snapshot!(cb17.disasm(), @" 0x0: mov r8w, 0xffff"); - assert_snapshot!(cb18.disasm(), @" 0x0: mov r8d, 1"); - assert_snapshot!(cb19.disasm(), @" 0x0: mov r8d, 0xffffffff"); - assert_snapshot!(cb20.disasm(), @" 0x0: mov r8d, 1"); - assert_snapshot!(cb21.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); - - assert_snapshot!(cb01.string(), @"b001"); - assert_snapshot!(cb02.string(), @"b0ff"); - assert_snapshot!(cb03.string(), @"66b80100"); - assert_snapshot!(cb04.string(), @"66b8ffff"); - assert_snapshot!(cb05.string(), @"b801000000"); - assert_snapshot!(cb06.string(), @"b8ffffffff"); - assert_snapshot!(cb07.string(), @"41b800000000"); - assert_snapshot!(cb08.string(), @"41b8ffffffff"); - assert_snapshot!(cb09.string(), @"b801000000"); - assert_snapshot!(cb10.string(), @"b8ffffffff"); - assert_snapshot!(cb11.string(), @"48b80000000001000000"); - assert_snapshot!(cb12.string(), @"48b8ffffffffffffffff"); - assert_snapshot!(cb13.string(), @"49b8ffffffffffffffff"); - assert_snapshot!(cb14.string(), @"41b001"); - assert_snapshot!(cb15.string(), @"41b0ff"); - assert_snapshot!(cb16.string(), @"6641b80100"); - assert_snapshot!(cb17.string(), @"6641b8ffff"); - assert_snapshot!(cb18.string(), @"41b801000000"); - assert_snapshot!(cb19.string(), @"41b8ffffffff"); - assert_snapshot!(cb20.string(), @"41b801000000"); - assert_snapshot!(cb21.string(), @"49b8ffffffffffffffff"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov al, 1")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov al, 0xff")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov ax, 1")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov ax, 0xffff")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 1")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 0xffffffff")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 0")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 0xffffffff")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 1")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 0xffffffff")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0x100000000")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0xffffffffffffffff")); + cb13.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0xffffffffffffffff")); + cb14.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8b, 1")); + cb15.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8b, 0xff")); + cb16.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8w, 1")); + cb17.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8w, 0xffff")); + cb18.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 1")); + cb19.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 0xffffffff")); + cb20.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r8d, 1")); + cb21.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r8, 0xffffffffffffffff")); + + assert_snapshot!(cb01.hexdump(), @"b001"); + assert_snapshot!(cb02.hexdump(), @"b0ff"); + assert_snapshot!(cb03.hexdump(), @"66b80100"); + assert_snapshot!(cb04.hexdump(), @"66b8ffff"); + assert_snapshot!(cb05.hexdump(), @"b801000000"); + assert_snapshot!(cb06.hexdump(), @"b8ffffffff"); + assert_snapshot!(cb07.hexdump(), @"41b800000000"); + assert_snapshot!(cb08.hexdump(), @"41b8ffffffff"); + assert_snapshot!(cb09.hexdump(), @"b801000000"); + assert_snapshot!(cb10.hexdump(), @"b8ffffffff"); + assert_snapshot!(cb11.hexdump(), @"48b80000000001000000"); + assert_snapshot!(cb12.hexdump(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb13.hexdump(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb14.hexdump(), @"41b001"); + assert_snapshot!(cb15.hexdump(), @"41b0ff"); + assert_snapshot!(cb16.hexdump(), @"6641b80100"); + assert_snapshot!(cb17.hexdump(), @"6641b8ffff"); + assert_snapshot!(cb18.hexdump(), @"41b801000000"); + assert_snapshot!(cb19.hexdump(), @"41b8ffffffff"); + assert_snapshot!(cb20.hexdump(), @"41b801000000"); + assert_snapshot!(cb21.hexdump(), @"49b8ffffffffffffffff"); } #[test] @@ -474,17 +474,17 @@ fn test_mov_iprel() { let cb4 = compile(|cb| mov(cb, RAX, mem_opnd(64, RIP, 5))); let cb5 = compile(|cb| mov(cb, RDI, mem_opnd(64, RIP, 5))); - assert_snapshot!(cb1.disasm(), @" 0x0: mov eax, dword ptr [rip]"); - assert_snapshot!(cb2.disasm(), @" 0x0: mov eax, dword ptr [rip + 5]"); - assert_snapshot!(cb3.disasm(), @" 0x0: mov rax, qword ptr [rip]"); - assert_snapshot!(cb4.disasm(), @" 0x0: mov rax, qword ptr [rip + 5]"); - assert_snapshot!(cb5.disasm(), @" 0x0: mov rdi, qword ptr [rip + 5]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, dword ptr [rip]")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, dword ptr [rip + 5]")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rax, qword ptr [rip]")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rax, qword ptr [rip + 5]")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov rdi, qword ptr [rip + 5]")); - assert_snapshot!(cb1.string(), @"8b0500000000"); - assert_snapshot!(cb2.string(), @"8b0505000000"); - assert_snapshot!(cb3.string(), @"488b0500000000"); - assert_snapshot!(cb4.string(), @"488b0505000000"); - assert_snapshot!(cb5.string(), @"488b3d05000000"); + assert_snapshot!(cb1.hexdump(), @"8b0500000000"); + assert_snapshot!(cb2.hexdump(), @"8b0505000000"); + assert_snapshot!(cb3.hexdump(), @"488b0500000000"); + assert_snapshot!(cb4.hexdump(), @"488b0505000000"); + assert_snapshot!(cb5.hexdump(), @"488b3d05000000"); } #[test] @@ -498,23 +498,23 @@ fn test_movsx() { let cb7 = compile(|cb| movsx(cb, RAX, mem_opnd(8, RSP, 0))); let cb8 = compile(|cb| movsx(cb, RDX, mem_opnd(16, R13, 4))); - assert_snapshot!(cb1.disasm(), @" 0x0: movsx ax, al"); - assert_snapshot!(cb2.disasm(), @" 0x0: movsx edx, al"); - assert_snapshot!(cb3.disasm(), @" 0x0: movsx rax, bl"); - assert_snapshot!(cb4.disasm(), @" 0x0: movsx ecx, ax"); - assert_snapshot!(cb5.disasm(), @" 0x0: movsx r11, cl"); - assert_snapshot!(cb6.disasm(), @" 0x0: movsxd r10, dword ptr [rsp + 0xc]"); - assert_snapshot!(cb7.disasm(), @" 0x0: movsx rax, byte ptr [rsp]"); - assert_snapshot!(cb8.disasm(), @" 0x0: movsx rdx, word ptr [r13 + 4]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx ax, al")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx edx, al")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx rax, bl")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx ecx, ax")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx r11, cl")); + cb6.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsxd r10, dword ptr [rsp + 0xc]")); + cb7.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx rax, byte ptr [rsp]")); + cb8.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movsx rdx, word ptr [r13 + 4]")); - assert_snapshot!(cb1.string(), @"660fbec0"); - assert_snapshot!(cb2.string(), @"0fbed0"); - assert_snapshot!(cb3.string(), @"480fbec3"); - assert_snapshot!(cb4.string(), @"0fbfc8"); - assert_snapshot!(cb5.string(), @"4c0fbed9"); - assert_snapshot!(cb6.string(), @"4c6354240c"); - assert_snapshot!(cb7.string(), @"480fbe0424"); - assert_snapshot!(cb8.string(), @"490fbf5504"); + assert_snapshot!(cb1.hexdump(), @"660fbec0"); + assert_snapshot!(cb2.hexdump(), @"0fbed0"); + assert_snapshot!(cb3.hexdump(), @"480fbec3"); + assert_snapshot!(cb4.hexdump(), @"0fbfc8"); + assert_snapshot!(cb5.hexdump(), @"4c0fbed9"); + assert_snapshot!(cb6.hexdump(), @"4c6354240c"); + assert_snapshot!(cb7.hexdump(), @"480fbe0424"); + assert_snapshot!(cb8.hexdump(), @"490fbf5504"); } #[test] @@ -532,40 +532,40 @@ fn test_nop() { let cb11 = compile(|cb| nop(cb, 11)); let cb12 = compile(|cb| nop(cb, 12)); - assert_snapshot!(cb01.disasm(), @" 0x0: nop"); - assert_snapshot!(cb02.disasm(), @" 0x0: nop"); - assert_snapshot!(cb03.disasm(), @" 0x0: nop dword ptr [rax]"); - assert_snapshot!(cb04.disasm(), @" 0x0: nop dword ptr [rax]"); - assert_snapshot!(cb05.disasm(), @" 0x0: nop dword ptr [rax + rax]"); - assert_snapshot!(cb06.disasm(), @" 0x0: nop word ptr [rax + rax]"); - assert_snapshot!(cb07.disasm(), @" 0x0: nop dword ptr [rax]"); - assert_snapshot!(cb08.disasm(), @" 0x0: nop dword ptr [rax + rax]"); - assert_snapshot!(cb09.disasm(), @" 0x0: nop word ptr [rax + rax]"); - assert_snapshot!(cb10.disasm(), @r" + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop dword ptr [rax]")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop dword ptr [rax]")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop dword ptr [rax + rax]")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop word ptr [rax + rax]")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop dword ptr [rax]")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop dword ptr [rax + rax]")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: nop word ptr [rax + rax]")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: nop word ptr [rax + rax] 0x9: nop - "); - assert_snapshot!(cb11.disasm(), @r" + ")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: nop word ptr [rax + rax] 0x9: nop - "); - assert_snapshot!(cb12.disasm(), @r" + ")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: nop word ptr [rax + rax] 0x9: nop dword ptr [rax] - "); + ")); - assert_snapshot!(cb01.string(), @"90"); - assert_snapshot!(cb02.string(), @"6690"); - assert_snapshot!(cb03.string(), @"0f1f00"); - assert_snapshot!(cb04.string(), @"0f1f4000"); - assert_snapshot!(cb05.string(), @"0f1f440000"); - assert_snapshot!(cb06.string(), @"660f1f440000"); - assert_snapshot!(cb07.string(), @"0f1f8000000000"); - assert_snapshot!(cb08.string(), @"0f1f840000000000"); - assert_snapshot!(cb09.string(), @"660f1f840000000000"); - assert_snapshot!(cb10.string(), @"660f1f84000000000090"); - assert_snapshot!(cb11.string(), @"660f1f8400000000006690"); - assert_snapshot!(cb12.string(), @"660f1f8400000000000f1f00"); + assert_snapshot!(cb01.hexdump(), @"90"); + assert_snapshot!(cb02.hexdump(), @"6690"); + assert_snapshot!(cb03.hexdump(), @"0f1f00"); + assert_snapshot!(cb04.hexdump(), @"0f1f4000"); + assert_snapshot!(cb05.hexdump(), @"0f1f440000"); + assert_snapshot!(cb06.hexdump(), @"660f1f440000"); + assert_snapshot!(cb07.hexdump(), @"0f1f8000000000"); + assert_snapshot!(cb08.hexdump(), @"0f1f840000000000"); + assert_snapshot!(cb09.hexdump(), @"660f1f840000000000"); + assert_snapshot!(cb10.hexdump(), @"660f1f84000000000090"); + assert_snapshot!(cb11.hexdump(), @"660f1f8400000000006690"); + assert_snapshot!(cb12.hexdump(), @"660f1f8400000000000f1f00"); } #[test] @@ -588,48 +588,48 @@ fn test_not() { let cb16 = compile(|cb| not(cb, mem_opnd(32, RDX, -55))); let cb17 = compile(|cb| not(cb, mem_opnd(32, RDX, -555))); - assert_snapshot!(cb01.disasm(), @" 0x0: not ax"); - assert_snapshot!(cb02.disasm(), @" 0x0: not eax"); - assert_snapshot!(cb03.disasm(), @" 0x0: not qword ptr [r12]"); - assert_snapshot!(cb04.disasm(), @" 0x0: not dword ptr [rsp + 0x12d]"); - assert_snapshot!(cb05.disasm(), @" 0x0: not dword ptr [rsp]"); - assert_snapshot!(cb06.disasm(), @" 0x0: not dword ptr [rsp + 3]"); - assert_snapshot!(cb07.disasm(), @" 0x0: not dword ptr [rbp]"); - assert_snapshot!(cb08.disasm(), @" 0x0: not dword ptr [rbp + 0xd]"); - assert_snapshot!(cb09.disasm(), @" 0x0: not rax"); - assert_snapshot!(cb10.disasm(), @" 0x0: not r11"); - assert_snapshot!(cb11.disasm(), @" 0x0: not dword ptr [rax]"); - assert_snapshot!(cb12.disasm(), @" 0x0: not dword ptr [rsi]"); - assert_snapshot!(cb13.disasm(), @" 0x0: not dword ptr [rdi]"); - assert_snapshot!(cb14.disasm(), @" 0x0: not dword ptr [rdx + 0x37]"); - assert_snapshot!(cb15.disasm(), @" 0x0: not dword ptr [rdx + 0x539]"); - assert_snapshot!(cb16.disasm(), @" 0x0: not dword ptr [rdx - 0x37]"); - assert_snapshot!(cb17.disasm(), @" 0x0: not dword ptr [rdx - 0x22b]"); - - assert_snapshot!(cb01.string(), @"66f7d0"); - assert_snapshot!(cb02.string(), @"f7d0"); - assert_snapshot!(cb03.string(), @"49f71424"); - assert_snapshot!(cb04.string(), @"f794242d010000"); - assert_snapshot!(cb05.string(), @"f71424"); - assert_snapshot!(cb06.string(), @"f7542403"); - assert_snapshot!(cb07.string(), @"f75500"); - assert_snapshot!(cb08.string(), @"f7550d"); - assert_snapshot!(cb09.string(), @"48f7d0"); - assert_snapshot!(cb10.string(), @"49f7d3"); - assert_snapshot!(cb11.string(), @"f710"); - assert_snapshot!(cb12.string(), @"f716"); - assert_snapshot!(cb13.string(), @"f717"); - assert_snapshot!(cb14.string(), @"f75237"); - assert_snapshot!(cb15.string(), @"f79239050000"); - assert_snapshot!(cb16.string(), @"f752c9"); - assert_snapshot!(cb17.string(), @"f792d5fdffff"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not ax")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not eax")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not qword ptr [r12]")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rsp + 0x12d]")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rsp]")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rsp + 3]")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rbp]")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rbp + 0xd]")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not rax")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not r11")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rax]")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rsi]")); + cb13.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rdi]")); + cb14.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rdx + 0x37]")); + cb15.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rdx + 0x539]")); + cb16.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rdx - 0x37]")); + cb17.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: not dword ptr [rdx - 0x22b]")); + + assert_snapshot!(cb01.hexdump(), @"66f7d0"); + assert_snapshot!(cb02.hexdump(), @"f7d0"); + assert_snapshot!(cb03.hexdump(), @"49f71424"); + assert_snapshot!(cb04.hexdump(), @"f794242d010000"); + assert_snapshot!(cb05.hexdump(), @"f71424"); + assert_snapshot!(cb06.hexdump(), @"f7542403"); + assert_snapshot!(cb07.hexdump(), @"f75500"); + assert_snapshot!(cb08.hexdump(), @"f7550d"); + assert_snapshot!(cb09.hexdump(), @"48f7d0"); + assert_snapshot!(cb10.hexdump(), @"49f7d3"); + assert_snapshot!(cb11.hexdump(), @"f710"); + assert_snapshot!(cb12.hexdump(), @"f716"); + assert_snapshot!(cb13.hexdump(), @"f717"); + assert_snapshot!(cb14.hexdump(), @"f75237"); + assert_snapshot!(cb15.hexdump(), @"f79239050000"); + assert_snapshot!(cb16.hexdump(), @"f752c9"); + assert_snapshot!(cb17.hexdump(), @"f792d5fdffff"); } #[test] fn test_or() { let cb = compile(|cb| or(cb, EDX, ESI)); - assert_snapshot!(cb.disasm(), @" 0x0: or edx, esi"); - assert_snapshot!(cb.string(), @"09f2"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: or edx, esi")); + assert_snapshot!(cb.hexdump(), @"09f2"); } #[test] @@ -645,27 +645,27 @@ fn test_pop() { let cb09 = compile(|cb| pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); let cb10 = compile(|cb| pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); - assert_snapshot!(cb01.disasm(), @" 0x0: pop rax"); - assert_snapshot!(cb02.disasm(), @" 0x0: pop rbx"); - assert_snapshot!(cb03.disasm(), @" 0x0: pop rsp"); - assert_snapshot!(cb04.disasm(), @" 0x0: pop rbp"); - assert_snapshot!(cb05.disasm(), @" 0x0: pop r12"); - assert_snapshot!(cb06.disasm(), @" 0x0: pop qword ptr [rax]"); - assert_snapshot!(cb07.disasm(), @" 0x0: pop qword ptr [r8]"); - assert_snapshot!(cb08.disasm(), @" 0x0: pop qword ptr [r8 + 3]"); - assert_snapshot!(cb09.disasm(), @" 0x0: pop qword ptr [rax + rcx*8 + 3]"); - assert_snapshot!(cb10.disasm(), @" 0x0: pop qword ptr [r8 + rcx*8 + 3]"); - - assert_snapshot!(cb01.string(), @"58"); - assert_snapshot!(cb02.string(), @"5b"); - assert_snapshot!(cb03.string(), @"5c"); - assert_snapshot!(cb04.string(), @"5d"); - assert_snapshot!(cb05.string(), @"415c"); - assert_snapshot!(cb06.string(), @"8f00"); - assert_snapshot!(cb07.string(), @"418f00"); - assert_snapshot!(cb08.string(), @"418f4003"); - assert_snapshot!(cb09.string(), @"8f44c803"); - assert_snapshot!(cb10.string(), @"418f44c803"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop rax")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop rbx")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop rsp")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop rbp")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop r12")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop qword ptr [rax]")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop qword ptr [r8]")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop qword ptr [r8 + 3]")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop qword ptr [rax + rcx*8 + 3]")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: pop qword ptr [r8 + rcx*8 + 3]")); + + assert_snapshot!(cb01.hexdump(), @"58"); + assert_snapshot!(cb02.hexdump(), @"5b"); + assert_snapshot!(cb03.hexdump(), @"5c"); + assert_snapshot!(cb04.hexdump(), @"5d"); + assert_snapshot!(cb05.hexdump(), @"415c"); + assert_snapshot!(cb06.hexdump(), @"8f00"); + assert_snapshot!(cb07.hexdump(), @"418f00"); + assert_snapshot!(cb08.hexdump(), @"418f4003"); + assert_snapshot!(cb09.hexdump(), @"8f44c803"); + assert_snapshot!(cb10.hexdump(), @"418f44c803"); } #[test] @@ -679,30 +679,30 @@ fn test_push() { let cb7 = compile(|cb| push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); let cb8 = compile(|cb| push(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); - assert_snapshot!(cb1.disasm(), @" 0x0: push rax"); - assert_snapshot!(cb2.disasm(), @" 0x0: push rbx"); - assert_snapshot!(cb3.disasm(), @" 0x0: push r12"); - assert_snapshot!(cb4.disasm(), @" 0x0: push qword ptr [rax]"); - assert_snapshot!(cb5.disasm(), @" 0x0: push qword ptr [r8]"); - assert_snapshot!(cb6.disasm(), @" 0x0: push qword ptr [r8 + 3]"); - assert_snapshot!(cb7.disasm(), @" 0x0: push qword ptr [rax + rcx*8 + 3]"); - assert_snapshot!(cb8.disasm(), @" 0x0: push qword ptr [r8 + rcx*8 + 3]"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push rax")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push rbx")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push r12")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push qword ptr [rax]")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push qword ptr [r8]")); + cb6.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push qword ptr [r8 + 3]")); + cb7.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push qword ptr [rax + rcx*8 + 3]")); + cb8.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push qword ptr [r8 + rcx*8 + 3]")); - assert_snapshot!(cb1.string(), @"50"); - assert_snapshot!(cb2.string(), @"53"); - assert_snapshot!(cb3.string(), @"4154"); - assert_snapshot!(cb4.string(), @"ff30"); - assert_snapshot!(cb5.string(), @"41ff30"); - assert_snapshot!(cb6.string(), @"41ff7003"); - assert_snapshot!(cb7.string(), @"ff74c803"); - assert_snapshot!(cb8.string(), @"41ff74c803"); + assert_snapshot!(cb1.hexdump(), @"50"); + assert_snapshot!(cb2.hexdump(), @"53"); + assert_snapshot!(cb3.hexdump(), @"4154"); + assert_snapshot!(cb4.hexdump(), @"ff30"); + assert_snapshot!(cb5.hexdump(), @"41ff30"); + assert_snapshot!(cb6.hexdump(), @"41ff7003"); + assert_snapshot!(cb7.hexdump(), @"ff74c803"); + assert_snapshot!(cb8.hexdump(), @"41ff74c803"); } #[test] fn test_ret() { let cb = compile(ret); - assert_snapshot!(cb.disasm(), @" 0x0: ret"); - assert_snapshot!(cb.string(), @"c3"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ret")); + assert_snapshot!(cb.hexdump(), @"c3"); } #[test] @@ -713,31 +713,31 @@ fn test_sal() { let cb4 = compile(|cb| sal(cb, mem_opnd(32, RSP, 68), uimm_opnd(1))); let cb5 = compile(|cb| sal(cb, RCX, CL)); - assert_snapshot!(cb1.disasm(), @" 0x0: shl cx, 1"); - assert_snapshot!(cb2.disasm(), @" 0x0: shl ecx, 1"); - assert_snapshot!(cb3.disasm(), @" 0x0: shl ebp, 5"); - assert_snapshot!(cb4.disasm(), @" 0x0: shl dword ptr [rsp + 0x44], 1"); - assert_snapshot!(cb5.disasm(), @" 0x0: shl rcx, cl"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shl cx, 1")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shl ecx, 1")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shl ebp, 5")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shl dword ptr [rsp + 0x44], 1")); + cb5.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shl rcx, cl")); - assert_snapshot!(cb1.string(), @"66d1e1"); - assert_snapshot!(cb2.string(), @"d1e1"); - assert_snapshot!(cb3.string(), @"c1e505"); - assert_snapshot!(cb4.string(), @"d1642444"); - assert_snapshot!(cb5.string(), @"48d3e1"); + assert_snapshot!(cb1.hexdump(), @"66d1e1"); + assert_snapshot!(cb2.hexdump(), @"d1e1"); + assert_snapshot!(cb3.hexdump(), @"c1e505"); + assert_snapshot!(cb4.hexdump(), @"d1642444"); + assert_snapshot!(cb5.hexdump(), @"48d3e1"); } #[test] fn test_sar() { let cb = compile(|cb| sar(cb, EDX, uimm_opnd(1))); - assert_snapshot!(cb.disasm(), @" 0x0: sar edx, 1"); - assert_snapshot!(cb.string(), @"d1fa"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sar edx, 1")); + assert_snapshot!(cb.hexdump(), @"d1fa"); } #[test] fn test_shr() { let cb = compile(|cb| shr(cb, R14, uimm_opnd(7))); - assert_snapshot!(cb.disasm(), @" 0x0: shr r14, 7"); - assert_snapshot!(cb.string(), @"49c1ee07"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: shr r14, 7")); + assert_snapshot!(cb.hexdump(), @"49c1ee07"); } #[test] @@ -745,11 +745,11 @@ fn test_sub() { let cb1 = compile(|cb| sub(cb, EAX, imm_opnd(1))); let cb2 = compile(|cb| sub(cb, RAX, imm_opnd(2))); - assert_snapshot!(cb1.disasm(), @" 0x0: sub eax, 1"); - assert_snapshot!(cb2.disasm(), @" 0x0: sub rax, 2"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub eax, 1")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub rax, 2")); - assert_snapshot!(cb1.string(), @"83e801"); - assert_snapshot!(cb2.string(), @"4883e802"); + assert_snapshot!(cb1.hexdump(), @"83e801"); + assert_snapshot!(cb2.hexdump(), @"4883e802"); } #[test] @@ -782,45 +782,45 @@ fn test_test() { let cb18 = compile(|cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(0x08))); let cb19 = compile(|cb| test(cb, RCX, imm_opnd(0x08))); - assert_snapshot!(cb01.disasm(), @" 0x0: test al, al"); - assert_snapshot!(cb02.disasm(), @" 0x0: test ax, ax"); - assert_snapshot!(cb03.disasm(), @" 0x0: test cl, 8"); - assert_snapshot!(cb04.disasm(), @" 0x0: test dl, 7"); - assert_snapshot!(cb05.disasm(), @" 0x0: test cl, 8"); - assert_snapshot!(cb06.disasm(), @" 0x0: test byte ptr [rdx + 8], 8"); - assert_snapshot!(cb07.disasm(), @" 0x0: test byte ptr [rdx + 8], 0xff"); - assert_snapshot!(cb08.disasm(), @" 0x0: test dx, 0xffff"); - assert_snapshot!(cb09.disasm(), @" 0x0: test word ptr [rdx + 8], 0xffff"); - assert_snapshot!(cb10.disasm(), @" 0x0: test byte ptr [rsi], 1"); - assert_snapshot!(cb11.disasm(), @" 0x0: test byte ptr [rsi + 0x10], 1"); - assert_snapshot!(cb12.disasm(), @" 0x0: test byte ptr [rsi - 0x10], 1"); - assert_snapshot!(cb13.disasm(), @" 0x0: test dword ptr [rsi + 0x40], eax"); - assert_snapshot!(cb14.disasm(), @" 0x0: test qword ptr [rdi + 0x2a], rax"); - assert_snapshot!(cb15.disasm(), @" 0x0: test rax, rax"); - assert_snapshot!(cb16.disasm(), @" 0x0: test rax, rsi"); - assert_snapshot!(cb17.disasm(), @" 0x0: test qword ptr [rsi + 0x40], -9"); - assert_snapshot!(cb18.disasm(), @" 0x0: test qword ptr [rsi + 0x40], 8"); - assert_snapshot!(cb19.disasm(), @" 0x0: test rcx, 8"); - - assert_snapshot!(cb01.string(), @"84c0"); - assert_snapshot!(cb02.string(), @"6685c0"); - assert_snapshot!(cb03.string(), @"f6c108"); - assert_snapshot!(cb04.string(), @"f6c207"); - assert_snapshot!(cb05.string(), @"f6c108"); - assert_snapshot!(cb06.string(), @"f6420808"); - assert_snapshot!(cb07.string(), @"f64208ff"); - assert_snapshot!(cb08.string(), @"66f7c2ffff"); - assert_snapshot!(cb09.string(), @"66f74208ffff"); - assert_snapshot!(cb10.string(), @"f60601"); - assert_snapshot!(cb11.string(), @"f6461001"); - assert_snapshot!(cb12.string(), @"f646f001"); - assert_snapshot!(cb13.string(), @"854640"); - assert_snapshot!(cb14.string(), @"4885472a"); - assert_snapshot!(cb15.string(), @"4885c0"); - assert_snapshot!(cb16.string(), @"4885f0"); - assert_snapshot!(cb17.string(), @"48f74640f7ffffff"); - assert_snapshot!(cb18.string(), @"48f7464008000000"); - assert_snapshot!(cb19.string(), @"48f7c108000000"); + cb01.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test al, al")); + cb02.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test ax, ax")); + cb03.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test cl, 8")); + cb04.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test dl, 7")); + cb05.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test cl, 8")); + cb06.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test byte ptr [rdx + 8], 8")); + cb07.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test byte ptr [rdx + 8], 0xff")); + cb08.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test dx, 0xffff")); + cb09.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test word ptr [rdx + 8], 0xffff")); + cb10.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test byte ptr [rsi], 1")); + cb11.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test byte ptr [rsi + 0x10], 1")); + cb12.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test byte ptr [rsi - 0x10], 1")); + cb13.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test dword ptr [rsi + 0x40], eax")); + cb14.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test qword ptr [rdi + 0x2a], rax")); + cb15.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test rax, rax")); + cb16.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test rax, rsi")); + cb17.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test qword ptr [rsi + 0x40], -9")); + cb18.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test qword ptr [rsi + 0x40], 8")); + cb19.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test rcx, 8")); + + assert_snapshot!(cb01.hexdump(), @"84c0"); + assert_snapshot!(cb02.hexdump(), @"6685c0"); + assert_snapshot!(cb03.hexdump(), @"f6c108"); + assert_snapshot!(cb04.hexdump(), @"f6c207"); + assert_snapshot!(cb05.hexdump(), @"f6c108"); + assert_snapshot!(cb06.hexdump(), @"f6420808"); + assert_snapshot!(cb07.hexdump(), @"f64208ff"); + assert_snapshot!(cb08.hexdump(), @"66f7c2ffff"); + assert_snapshot!(cb09.hexdump(), @"66f74208ffff"); + assert_snapshot!(cb10.hexdump(), @"f60601"); + assert_snapshot!(cb11.hexdump(), @"f6461001"); + assert_snapshot!(cb12.hexdump(), @"f646f001"); + assert_snapshot!(cb13.hexdump(), @"854640"); + assert_snapshot!(cb14.hexdump(), @"4885472a"); + assert_snapshot!(cb15.hexdump(), @"4885c0"); + assert_snapshot!(cb16.hexdump(), @"4885f0"); + assert_snapshot!(cb17.hexdump(), @"48f74640f7ffffff"); + assert_snapshot!(cb18.hexdump(), @"48f7464008000000"); + assert_snapshot!(cb19.hexdump(), @"48f7c108000000"); } #[test] @@ -830,22 +830,22 @@ fn test_xchg() { let cb3 = compile(|cb| xchg(cb, RCX, RBX)); let cb4 = compile(|cb| xchg(cb, R9, R15)); - assert_snapshot!(cb1.disasm(), @" 0x0: xchg rcx, rax"); - assert_snapshot!(cb2.disasm(), @" 0x0: xchg r13, rax"); - assert_snapshot!(cb3.disasm(), @" 0x0: xchg rcx, rbx"); - assert_snapshot!(cb4.disasm(), @" 0x0: xchg r9, r15"); + cb1.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xchg rcx, rax")); + cb2.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xchg r13, rax")); + cb3.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xchg rcx, rbx")); + cb4.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xchg r9, r15")); - assert_snapshot!(cb1.string(), @"4891"); - assert_snapshot!(cb2.string(), @"4995"); - assert_snapshot!(cb3.string(), @"4887d9"); - assert_snapshot!(cb4.string(), @"4d87f9"); + assert_snapshot!(cb1.hexdump(), @"4891"); + assert_snapshot!(cb2.hexdump(), @"4995"); + assert_snapshot!(cb3.hexdump(), @"4887d9"); + assert_snapshot!(cb4.hexdump(), @"4d87f9"); } #[test] fn test_xor() { let cb = compile(|cb| xor(cb, EAX, EAX)); - assert_snapshot!(cb.disasm(), @" 0x0: xor eax, eax"); - assert_snapshot!(cb.string(), @"31c0"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xor eax, eax")); + assert_snapshot!(cb.hexdump(), @"31c0"); } #[test] diff --git a/zjit/src/backend/arm64/mod.rs b/zjit/src/backend/arm64/mod.rs index b1b898f38d913b..8168f416d09d11 100644 --- a/zjit/src/backend/arm64/mod.rs +++ b/zjit/src/backend/arm64/mod.rs @@ -1441,12 +1441,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, #3 0x4: mul x0, x9, x0 0x8: mov x1, x0 - "); - assert_snapshot!(cb.string(), @"600080d2207d009be10300aa"); + ")); + assert_snapshot!(cb.hexdump(), @"600080d2207d009be10300aa"); } #[test] @@ -1460,11 +1460,11 @@ mod tests { asm.mov(sp, new_sp); asm.compile_with_num_regs(&mut cb, 2); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add sp, sp, #0x20 0x4: sub sp, sp, #0x20 - "); - assert_snapshot!(cb.string(), @"ff830091ff8300d1"); + ")); + assert_snapshot!(cb.hexdump(), @"ff830091ff8300d1"); } #[test] @@ -1476,11 +1476,11 @@ mod tests { asm.add_into(Opnd::Reg(X20_REG), 0x20.into()); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add sp, sp, #8 0x4: adds x20, x20, #0x20 - "); - assert_snapshot!(cb.string(), @"ff230091948200b1"); + ")); + assert_snapshot!(cb.hexdump(), @"ff230091948200b1"); } #[test] @@ -1491,12 +1491,12 @@ mod tests { asm.load_into(Opnd::Reg(X1_REG), difference); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, #8 0x4: subs x0, x0, x5 0x8: mov x1, x0 - "); - assert_snapshot!(cb.string(), @"000180d2000005ebe10300aa"); + ")); + assert_snapshot!(cb.hexdump(), @"000180d2000005ebe10300aa"); } #[test] @@ -1507,11 +1507,11 @@ mod tests { asm.cret(ret_val); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldur x0, [x0] 0x4: ret - "); - assert_snapshot!(cb.string(), @"000040f8c0035fd6"); + ")); + assert_snapshot!(cb.hexdump(), @"000040f8c0035fd6"); } #[test] @@ -1572,7 +1572,7 @@ mod tests { asm.frame_setup(THREE_REGS, 3); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1582,8 +1582,8 @@ mod tests { 0x18: ldur x21, [x29, #-0x18] 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 - "); - assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); + ")); + assert_snapshot!(cb.hexdump(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 3 preserved regs (odd), even slot_count @@ -1592,7 +1592,7 @@ mod tests { asm.frame_setup(THREE_REGS, 4); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1602,8 +1602,8 @@ mod tests { 0x18: ldur x21, [x29, #-0x18] 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 - "); - assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); + ")); + assert_snapshot!(cb.hexdump(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 4 preserved regs (even), odd slot_count @@ -1613,7 +1613,7 @@ mod tests { asm.frame_setup(FOUR_REGS, 3); asm.frame_teardown(FOUR_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1623,8 +1623,8 @@ mod tests { 0x18: ldp x22, x21, [x29, #-0x20] 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 - "); - assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8"); + ")); + assert_snapshot!(cb.hexdump(), @"fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8"); } } @@ -1664,7 +1664,7 @@ mod tests { } asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: orr x0, xzr, #0x7fffffff 0x4: add x0, sp, x0 0x8: mov x0, #8 @@ -1683,8 +1683,8 @@ mod tests { 0x3c: add x0, sp, x0 0x40: orr x0, xzr, #0xffffffff80000000 0x44: add x0, sp, x0 - "); - assert_snapshot!(cb.string(), @"e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b"); + ")); + assert_snapshot!(cb.hexdump(), @"e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b"); } #[test] @@ -1699,7 +1699,7 @@ mod tests { asm.store(large_mem, large_mem); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub x16, sp, #0x305 0x4: ldur x16, [x16] 0x8: stur x16, [x0] @@ -1710,8 +1710,8 @@ mod tests { 0x1c: ldur x16, [x16] 0x20: sub x17, sp, #0x305 0x24: stur x16, [x17] - "); - assert_snapshot!(cb.string(), @"f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8"); + ")); + assert_snapshot!(cb.hexdump(), @"f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8"); } #[test] @@ -1727,14 +1727,14 @@ mod tests { let gc_offsets = asm.arm64_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldr x16, #8 0x4: b #0x10 0x8: .byte 0x00, 0x10, 0x00, 0x00 0xc: .byte 0x00, 0x00, 0x00, 0x00 0x10: stur x16, [x21] - "); - assert_snapshot!(cb.string(), @"50000058030000140010000000000000b00200f8"); + ")); + assert_snapshot!(cb.hexdump(), @"50000058030000140010000000000000b00200f8"); } #[test] @@ -1979,11 +1979,11 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: eor x0, x0, x1 0x4: stur x0, [x2] - "); - assert_snapshot!(cb.string(), @"000001ca400000f8"); + ")); + assert_snapshot!(cb.hexdump(), @"000001ca400000f8"); } #[test] @@ -2017,8 +2017,8 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::mem(64, CFP, 8)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: ldur x1, [x19, #8]"); - assert_snapshot!(cb.string(), @"618240f8"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: ldur x1, [x19, #8]")); + assert_snapshot!(cb.hexdump(), @"618240f8"); } #[test] @@ -2029,11 +2029,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::UImm(0x10000)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x1, #0xffff 0x4: orr x1, xzr, #0x10000 - "); - assert_snapshot!(cb.string(), @"e1ff9fd2e10370b2"); + ")); + assert_snapshot!(cb.hexdump(), @"e1ff9fd2e10370b2"); } #[test] @@ -2044,12 +2044,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x0, #0x14 0x4: mov x1, #0 0x8: csel x1, x0, x1, lt - "); - assert_snapshot!(cb.string(), @"800280d2010080d201b0819a"); + ")); + assert_snapshot!(cb.hexdump(), @"800280d2010080d201b0819a"); } #[test] @@ -2087,11 +2087,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: adds x0, x9, #1 0x4: adds x1, x0, #1 - "); - assert_snapshot!(cb.string(), @"200500b1010400b1"); + ")); + assert_snapshot!(cb.hexdump(), @"200500b1010400b1"); } #[test] @@ -2105,11 +2105,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x16, #0 0x4: blr x16 - "); - assert_snapshot!(cb.string(), @"100080d200023fd6"); + ")); + assert_snapshot!(cb.hexdump(), @"100080d200023fd6"); } #[test] @@ -2125,14 +2125,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x16 0xc: mov x16, #0 0x10: blr x16 - "); - assert_snapshot!(cb.string(), @"f00300aae00301aae10310aa100080d200023fd6"); + ")); + assert_snapshot!(cb.hexdump(), @"f00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2149,7 +2149,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x16, x2 0x4: mov x2, x3 0x8: mov x3, x16 @@ -2158,8 +2158,8 @@ mod tests { 0x14: mov x1, x16 0x18: mov x16, #0 0x1c: blr x16 - "); - assert_snapshot!(cb.string(), @"f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6"); + ")); + assert_snapshot!(cb.hexdump(), @"f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2175,14 +2175,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x2 0xc: mov x2, x16 0x10: mov x16, #0 0x14: blr x16 - "); - assert_snapshot!(cb.string(), @"f00300aae00301aae10302aae20310aa100080d200023fd6"); + ")); + assert_snapshot!(cb.hexdump(), @"f00300aae00301aae10302aae20310aa100080d200023fd6"); } } diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index 04430955096048..86856461f1910d 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -934,11 +934,11 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: add rax, 0xff - "); - assert_snapshot!(cb.string(), @"4889c04881c0ff000000"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c04881c0ff000000"); } #[test] @@ -949,12 +949,12 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: movabs r11, 0xffffffffffff 0xd: add rax, r11 - "); - assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c01d8"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c049bbffffffffffff00004c01d8"); } #[test] @@ -965,11 +965,11 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: and rax, 0xff - "); - assert_snapshot!(cb.string(), @"4889c04881e0ff000000"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c04881e0ff000000"); } #[test] @@ -980,12 +980,12 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: movabs r11, 0xffffffffffff 0xd: and rax, r11 - "); - assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c21d8"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c049bbffffffffffff00004c21d8"); } #[test] @@ -995,8 +995,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, 0xff"); - assert_snapshot!(cb.string(), @"4881f8ff000000"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp rax, 0xff")); + assert_snapshot!(cb.hexdump(), @"4881f8ff000000"); } #[test] @@ -1006,11 +1006,11 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: movabs r11, 0xffffffffffff 0xa: cmp rax, r11 - "); - assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); + ")); + assert_snapshot!(cb.hexdump(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1020,8 +1020,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, -1"); - assert_snapshot!(cb.string(), @"4883f8ff"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp rax, -1")); + assert_snapshot!(cb.hexdump(), @"4883f8ff"); } #[test] @@ -1033,8 +1033,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" 0x0: cmp word ptr [rax + 6], 0xf000"); - assert_snapshot!(cb.string(), @"6681780600f0"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp word ptr [rax + 6], 0xf000")); + assert_snapshot!(cb.hexdump(), @"6681780600f0"); } #[test] @@ -1046,8 +1046,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000_0000)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" 0x0: cmp dword ptr [rax + 4], 0xf0000000"); - assert_snapshot!(cb.string(), @"817804000000f0"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp dword ptr [rax + 4], 0xf0000000")); + assert_snapshot!(cb.hexdump(), @"817804000000f0"); } #[test] @@ -1058,11 +1058,11 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: or rax, 0xff - "); - assert_snapshot!(cb.string(), @"4889c04881c8ff000000"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c04881c8ff000000"); } #[test] @@ -1073,12 +1073,12 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: movabs r11, 0xffffffffffff 0xd: or rax, r11 - "); - assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c09d8"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c049bbffffffffffff00004c09d8"); } #[test] @@ -1089,11 +1089,11 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: sub rax, 0xff - "); - assert_snapshot!(cb.string(), @"4889c04881e8ff000000"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c04881e8ff000000"); } #[test] @@ -1104,12 +1104,12 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: movabs r11, 0xffffffffffff 0xd: sub rax, r11 - "); - assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c29d8"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c049bbffffffffffff00004c29d8"); } #[test] @@ -1119,8 +1119,8 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" 0x0: test rax, 0xff"); - assert_snapshot!(cb.string(), @"48f7c0ff000000"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: test rax, 0xff")); + assert_snapshot!(cb.hexdump(), @"48f7c0ff000000"); } #[test] @@ -1130,11 +1130,11 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: movabs r11, 0xffffffffffff 0xa: test rax, r11 - "); - assert_snapshot!(cb.string(), @"49bbffffffffffff00004c85d8"); + ")); + assert_snapshot!(cb.hexdump(), @"49bbffffffffffff00004c85d8"); } #[test] @@ -1145,11 +1145,11 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: xor rax, 0xff - "); - assert_snapshot!(cb.string(), @"4889c04881f0ff000000"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c04881f0ff000000"); } #[test] @@ -1160,12 +1160,12 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, rax 0x3: movabs r11, 0xffffffffffff 0xd: xor rax, r11 - "); - assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c31d8"); + ")); + assert_snapshot!(cb.hexdump(), @"4889c049bbffffffffffff00004c31d8"); } #[test] @@ -1176,8 +1176,8 @@ mod tests { asm.mov(SP, sp); // should be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: lea rbx, [rbx + 8]"); - assert_snapshot!(cb.string(), @"488d5b08"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: lea rbx, [rbx + 8]")); + assert_snapshot!(cb.hexdump(), @"488d5b08"); } #[test] @@ -1189,11 +1189,11 @@ mod tests { asm.mov(Opnd::mem(64, SP, 0), sp); // should NOT be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: movabs r11, 0xffffffffffff 0xa: cmp rax, r11 - "); - assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); + ")); + assert_snapshot!(cb.hexdump(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1207,15 +1207,15 @@ mod tests { asm.mov(Opnd::Reg(RAX_REG), result); asm.compile_with_num_regs(&mut cb, 2); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov rax, qword ptr [rbx + 8] 0x4: test rax, rax 0x7: mov eax, 0x14 0xc: mov ecx, 0 0x11: cmovne rax, rcx 0x15: mov rax, rax - "); - assert_snapshot!(cb.string(), @"488b43084885c0b814000000b900000000480f45c14889c0"); + ")); + assert_snapshot!(cb.hexdump(), @"488b43084885c0b814000000b900000000480f45c14889c0"); } #[test] @@ -1226,8 +1226,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); - assert_snapshot!(cb.string(), @"4983c540"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983c540"); } #[test] @@ -1237,8 +1237,8 @@ mod tests { asm.add_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); - assert_snapshot!(cb.string(), @"4983c540"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: add r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983c540"); } #[test] @@ -1249,8 +1249,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); - assert_snapshot!(cb.string(), @"4983ed40"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983ed40"); } #[test] @@ -1260,8 +1260,8 @@ mod tests { asm.sub_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); - assert_snapshot!(cb.string(), @"4983ed40"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: sub r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983ed40"); } #[test] @@ -1272,8 +1272,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: and r13, 0x40"); - assert_snapshot!(cb.string(), @"4983e540"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: and r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983e540"); } #[test] @@ -1284,8 +1284,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: or r13, 0x40"); - assert_snapshot!(cb.string(), @"4983cd40"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: or r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983cd40"); } #[test] @@ -1296,8 +1296,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" 0x0: xor r13, 0x40"); - assert_snapshot!(cb.string(), @"4983f540"); + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: xor r13, 0x40")); + assert_snapshot!(cb.hexdump(), @"4983f540"); } #[test] @@ -1311,11 +1311,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @r" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @r" 0x0: mov eax, 0 0x5: call rax - "); - assert_snapshot!(cb.string(), @"b800000000ffd0"); + ")); + assert_snapshot!(cb.hexdump(), @"b800000000ffd0"); } #[test] @@ -1331,14 +1331,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 0x9: mov eax, 0 0xe: call rax - "); - assert_snapshot!(cb.string(), @"4989f34889fe4c89dfb800000000ffd0"); + ")); + assert_snapshot!(cb.hexdump(), @"4989f34889fe4c89dfb800000000ffd0"); } #[test] @@ -1355,7 +1355,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 @@ -1364,8 +1364,8 @@ mod tests { 0xf: mov rdx, r11 0x12: mov eax, 0 0x17: call rax - "); - assert_snapshot!(cb.string(), @"4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0"); + ")); + assert_snapshot!(cb.hexdump(), @"4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1381,15 +1381,15 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov r11, rsi 0x3: mov rsi, rdx 0x6: mov rdx, rdi 0x9: mov rdi, r11 0xc: mov eax, 0 0x11: call rax - "); - assert_snapshot!(cb.string(), @"4989f34889d64889fa4c89dfb800000000ffd0"); + ")); + assert_snapshot!(cb.hexdump(), @"4989f34889d64889fa4c89dfb800000000ffd0"); } #[test] @@ -1409,7 +1409,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, 3); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov eax, 1 0x5: mov ecx, 2 0xa: mov edx, 3 @@ -1420,8 +1420,8 @@ mod tests { 0x1b: mov rdx, r11 0x1e: mov eax, 0 0x23: call rax - "); - assert_snapshot!(cb.string(), @"b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0"); + ")); + assert_snapshot!(cb.hexdump(), @"b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1438,13 +1438,13 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: cmp qword ptr [rbx + 0x10], 1 0x5: mov edi, 4 0xa: cmovg rdi, qword ptr [rbx] 0xe: mov qword ptr [rbx], rdi - "); - assert_snapshot!(cb.string(), @"48837b1001bf04000000480f4f3b48893b"); + ")); + assert_snapshot!(cb.hexdump(), @"48837b1001bf04000000480f4f3b48893b"); } #[test] @@ -1458,13 +1458,14 @@ mod tests { asm.compile_with_num_regs(&mut cb, 3); - assert_snapshot!(cb.disasm(), @" + #[cfg(feature = "disasm")] + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs rax, 0x7f22c88d1930 0xa: mov ecx, 4 0xf: cmove rax, rcx 0x13: mov qword ptr [rbx], rax - "); - assert_snapshot!(cb.string(), @"48b830198dc8227f0000b904000000480f44c1488903"); + ")); + assert_snapshot!(cb.hexdump(), @"48b830198dc8227f0000b904000000480f44c1488903"); } #[test] @@ -1476,11 +1477,12 @@ mod tests { asm.mov(shape_opnd, Opnd::Imm(0x8000_0001)); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + #[cfg(feature = "disasm")] + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: mov dword ptr [rax], 0x80000001 0x6: mov dword ptr [rax], 0x80000001 - "); - assert_snapshot!(cb.string(), @"c70001000080c70001000080"); + ")); + assert_snapshot!(cb.hexdump(), @"c70001000080c70001000080"); } #[test] @@ -1495,7 +1497,7 @@ mod tests { asm.frame_teardown(&[]); asm.compile_with_num_regs(&mut cb, 0); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: push rbp 0x1: mov rbp, rsp 0x4: push r13 @@ -1513,8 +1515,8 @@ mod tests { 0x22: sub rsp, 0x30 0x26: mov rsp, rbp 0x29: pop rbp - "); - assert_snapshot!(cb.string(), @"554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d"); + ")); + assert_snapshot!(cb.hexdump(), @"554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d"); } #[test] @@ -1528,10 +1530,10 @@ mod tests { let gc_offsets = asm.x86_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_snapshot!(cb.disasm(), @" + cb.with_disasm(|disasm| assert_snapshot!(disasm, @" 0x0: movabs r11, 0x1000 0xa: mov qword ptr [rbx], r11 - "); - assert_snapshot!(cb.string(), @"49bb00100000000000004c891b"); + ")); + assert_snapshot!(cb.hexdump(), @"49bb00100000000000004c891b"); } } From 7c51ce5ff625c1295d48ff041b22cb4a9d75c9aa Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 18 Sep 2025 17:20:01 -0700 Subject: [PATCH 13/22] Mark list as frozen and shareable --- encoding.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/encoding.c b/encoding.c index bda40eb04392c7..e2c061480ef71e 100644 --- a/encoding.c +++ b/encoding.c @@ -152,6 +152,8 @@ enc_list_update(int index, rb_raw_encoding *encoding) RBASIC_CLEAR_CLASS(new_list); /* initialize encoding data */ rb_ary_store(new_list, index, enc_new(encoding)); + rb_ary_freeze(new_list); + FL_SET_RAW(new_list, RUBY_FL_SHAREABLE); RUBY_ATOMIC_VALUE_SET(rb_encoding_list, new_list); } } From f048f77c4a0bf9cb604e2f3291dda71978ed8313 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 18 Sep 2025 16:31:58 -0700 Subject: [PATCH 14/22] Extract enc_load_from_base from enc_register_at Previously we would sometimes call enc_register_at several times in order to update the encoding values after the base encoding may have been loaded. This updates enc_register_at to only be used via enc_register, when an actual new encoding at a new index is being registered. Other callers (which in all cases found the index by the name matching) now call enc_load_from_base which is only responsibly for loading the encoding from the base values. --- encoding.c | 93 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/encoding.c b/encoding.c index e2c061480ef71e..4ccb29d2a1a512 100644 --- a/encoding.c +++ b/encoding.c @@ -351,6 +351,35 @@ enc_table_expand(struct enc_table *enc_table, int newsize) return newsize; } +/* Load an encoding using the values from base_encoding */ +static void +enc_load_from_base(struct enc_table *enc_table, int index, rb_encoding *base_encoding) +{ + ASSERT_vm_locking(); + + struct rb_encoding_entry *ent = &enc_table->list[index]; + + if (ent->loaded) { + return; + } + + rb_raw_encoding *encoding = (rb_raw_encoding *)ent->enc; + RUBY_ASSERT(encoding); + + // FIXME: Before the base is loaded, the encoding may be accessed + // concurrently by other Ractors. + // We're copying all fields from base_encoding except name and + // ruby_encoding_index which we preserve from the original. Since these are + // the only fields other threads should read it is likely safe despite + // technically being a data race. + rb_raw_encoding tmp_encoding = *base_encoding; + tmp_encoding.name = encoding->name; + tmp_encoding.ruby_encoding_index = encoding->ruby_encoding_index; + *encoding = tmp_encoding; + + RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len); +} + static int enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_encoding *base_encoding) { @@ -359,45 +388,33 @@ enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_enc struct rb_encoding_entry *ent = &enc_table->list[index]; rb_raw_encoding *encoding; - if (ent->loaded) { - RUBY_ASSERT(ent->base == base_encoding); - RUBY_ASSERT(!strcmp(name, ent->name)); - return index; - } + RUBY_ASSERT(!ent->loaded); + RUBY_ASSERT(!ent->name); + RUBY_ASSERT(!ent->enc); + RUBY_ASSERT(!ent->base); - if (!valid_encoding_name_p(name)) return -1; - if (!ent->name) { - ent->name = name = strdup(name); - } - else if (STRCASECMP(name, ent->name)) { - return -1; - } - encoding = (rb_raw_encoding *)ent->enc; - if (!encoding) { - encoding = xmalloc(sizeof(rb_encoding)); - } + RUBY_ASSERT(valid_encoding_name_p(name)); - rb_raw_encoding tmp_encoding; - if (base_encoding) { - tmp_encoding = *base_encoding; - } - else { - memset(&tmp_encoding, 0, sizeof(*ent->enc)); - } - tmp_encoding.name = name; - tmp_encoding.ruby_encoding_index = index; + ent->name = name = strdup(name); - // FIXME: If encoding already existed, it may be concurrently accessed - // It's technically invalid to write to this memory as it's read, but as all - // values are set up it _probably_ works. - *encoding = tmp_encoding; + encoding = ZALLOC(rb_raw_encoding); + encoding->name = name; + encoding->ruby_encoding_index = index; ent->enc = encoding; - st_insert(enc_table->names, (st_data_t)name, (st_data_t)index); + + if (st_insert(enc_table->names, (st_data_t)name, (st_data_t)index)) { + rb_bug("encoding name was somehow registered twice"); + } enc_list_update(index, encoding); - // max_enc_len is used to mark a fully loaded encoding. - RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len); + if (base_encoding) { + enc_load_from_base(enc_table, index, base_encoding); + } + else { + /* it should not be loaded yet */ + RUBY_ASSERT(!encoding->max_enc_len); + } return index; } @@ -407,6 +424,8 @@ enc_register(struct enc_table *enc_table, const char *name, rb_encoding *encodin { ASSERT_vm_locking(); + if (!valid_encoding_name_p(name)) return -1; + int index = enc_table->count; enc_table->count = enc_table_expand(enc_table, index + 1); @@ -447,7 +466,7 @@ rb_enc_register(const char *name, rb_encoding *encoding) index = enc_register(enc_table, name, encoding); } else if (rb_enc_autoload_p(oldenc) || !ENC_DUMMY_P(oldenc)) { - enc_register_at(enc_table, index, name, encoding); + enc_load_from_base(enc_table, index, encoding); } else { rb_raise(rb_eArgError, "encoding %s is already registered", name); @@ -564,7 +583,7 @@ enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encod idx = enc_register(enc_table, name, origenc); } else { - idx = enc_register_at(enc_table, idx, name, origenc); + enc_load_from_base(enc_table, idx, origenc); } if (idx >= 0) { set_base_encoding(enc_table, idx, origenc); @@ -841,13 +860,11 @@ enc_autoload_body(rb_encoding *enc) if (do_register) { GLOBAL_ENC_TABLE_LOCKING(enc_table) { - i = enc->ruby_encoding_index; - enc_register_at(enc_table, i & ENC_INDEX_MASK, rb_enc_name(enc), base); + i = ENC_TO_ENCINDEX(enc); + enc_load_from_base(enc_table, i, base); RUBY_ASSERT(((rb_raw_encoding *)enc)->ruby_encoding_index == i); } } - - i &= ENC_INDEX_MASK; } else { i = -2; From 02d5b8443a0f77bf498d29c0121e035f4deeaa27 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 18 Sep 2025 22:02:38 -0700 Subject: [PATCH 15/22] Simplify enc_autoload_body Previously we were looping over the enc_table, but when I added an assertion the only thing that loop was doing is the equivalent of ENC_TO_ENCINDEX(base). However we don't even need the index of base. Instead we should be able to just use the badirectly. --- encoding.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/encoding.c b/encoding.c index 4ccb29d2a1a512..da434cda1a4ff0 100644 --- a/encoding.c +++ b/encoding.c @@ -837,38 +837,27 @@ enc_autoload_body(rb_encoding *enc) GLOBAL_ENC_TABLE_LOCKING(enc_table) { base = enc_table->list[ENC_TO_ENCINDEX(enc)].base; - if (base) { - do { - if (i >= enc_table->count) { - i = -1; - break; - } - } while (enc_table->list[i].enc != base && (++i, 1)); - } } - - if (i != -1) { - if (base) { - bool do_register = true; - if (rb_enc_autoload_p(base)) { - if (rb_enc_autoload(base) < 0) { - do_register = false; - i = -1; - } + if (base) { + bool do_register = true; + if (rb_enc_autoload_p(base)) { + if (rb_enc_autoload(base) < 0) { + do_register = false; + i = -1; } + } - if (do_register) { - GLOBAL_ENC_TABLE_LOCKING(enc_table) { - i = ENC_TO_ENCINDEX(enc); - enc_load_from_base(enc_table, i, base); - RUBY_ASSERT(((rb_raw_encoding *)enc)->ruby_encoding_index == i); - } + if (do_register) { + GLOBAL_ENC_TABLE_LOCKING(enc_table) { + i = ENC_TO_ENCINDEX(enc); + enc_load_from_base(enc_table, i, base); + RUBY_ASSERT(((rb_raw_encoding *)enc)->ruby_encoding_index == i); } } - else { - i = -2; - } + } + else { + i = -2; } return i; From 6afbbb11785e483c7dba2a803e611904d32ec01f Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 19 Sep 2025 15:50:15 -0700 Subject: [PATCH 16/22] ZJIT: Remove unnecessary empty lines --- zjit/src/backend/arm64/mod.rs | 2 -- zjit/src/backend/x86_64/mod.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/zjit/src/backend/arm64/mod.rs b/zjit/src/backend/arm64/mod.rs index 8168f416d09d11..34e939957f702a 100644 --- a/zjit/src/backend/arm64/mod.rs +++ b/zjit/src/backend/arm64/mod.rs @@ -78,7 +78,6 @@ impl From for A64Opnd { Opnd::None => panic!( "Attempted to lower an Opnd::None. This often happens when an out operand was not allocated for an instruction because the output of the instruction was not used. Please ensure you are using the output." ), - } } } @@ -809,7 +808,6 @@ impl Assembler } emit_load_value(cb, Assembler::SCRATCH0, dst_addr); br(cb, Assembler::SCRATCH0); - } */ } else { diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index 86856461f1910d..d857c017dc72d4 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -605,7 +605,6 @@ impl Assembler scratch } src @ (Opnd::None | Opnd::VReg { .. }) => panic!("Unexpected source operand during x86_emit: {src:?}") - }; mov(cb, dest.into(), src); } From b19e3b0f060586dae91b567794128efb747b3f24 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sat, 20 Sep 2025 00:03:02 +0100 Subject: [PATCH 17/22] ZJIT: Avoid unnecessary `PopOpnds` and `PushOpnds` codegen (#14614) * ZJIT: Avoid unnecessary `PopOpnds` codegen If there's no opnds to restore, we don't need to do anything. * ZJIT: Avoid unnecessary sub_into when there's no opnds to allocate --- zjit/src/codegen.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 7185c171c133d9..0b236d0b57f4ef 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -2006,8 +2006,12 @@ fn gen_push_opnds(jit: &mut JITState, asm: &mut Assembler, opnds: &[Opnd]) -> li let frame_size = aligned_stack_bytes(jit.c_stack_slots); let allocation_size = aligned_stack_bytes(n); - asm_comment!(asm, "allocate {} bytes on C stack for {} values", allocation_size, n); - asm.sub_into(NATIVE_STACK_PTR, allocation_size.into()); + if n != 0 { + asm_comment!(asm, "allocate {} bytes on C stack for {} values", allocation_size, n); + asm.sub_into(NATIVE_STACK_PTR, allocation_size.into()); + } else { + asm_comment!(asm, "no opnds to allocate"); + } // Calculate the total offset from NATIVE_BASE_PTR to our buffer let total_offset_from_base = (frame_size + allocation_size) as i32; @@ -2024,6 +2028,11 @@ fn gen_push_opnds(jit: &mut JITState, asm: &mut Assembler, opnds: &[Opnd]) -> li } fn gen_pop_opnds(asm: &mut Assembler, opnds: &[Opnd]) { + if opnds.is_empty() { + asm_comment!(asm, "no opnds to restore"); + return + } + asm_comment!(asm, "restore C stack pointer"); let allocation_size = aligned_stack_bytes(opnds.len()); asm.add_into(NATIVE_STACK_PTR, allocation_size.into()); From 4a04e6f7555c94e0e58ad090681e359c7dcbf22e Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Thu, 18 Sep 2025 11:41:46 -0400 Subject: [PATCH 18/22] ZJIT: Wrap comment --- zjit/src/hir.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 1cc029492953c3..449646024a03a3 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -1970,7 +1970,8 @@ impl Function { // a singleton class, or has a custom allocator, ObjectAlloc might raise an // exception or run arbitrary code. // - // We also need to check if the class is initialized or a singleton before trying to read the allocator, otherwise it might raise. + // We also need to check if the class is initialized or a singleton before + // trying to read the allocator, otherwise it might raise. if !unsafe { rb_zjit_class_initialized_p(class) } { self.push_insn_id(block, insn_id); continue; } From 254b9b4952156ee443b920e89fec7b6d16a0f785 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Thu, 18 Sep 2025 13:47:35 -0400 Subject: [PATCH 19/22] ZJIT: Expand the list of safe allocators It's not just the default allocator; other allocators are also leaf. --- zjit/bindgen/src/main.rs | 1 + zjit/src/codegen.rs | 13 ++- zjit/src/cruby.rs | 13 +++ zjit/src/cruby_bindings.inc.rs | 1 + zjit/src/hir.rs | 163 ++++++++++++++++++++++++++++++++- 5 files changed, 186 insertions(+), 5 deletions(-) diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index c4fd625818044a..c4233521cce7fc 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -336,6 +336,7 @@ fn main() { .allowlist_function("rb_yarv_class_of") .allowlist_function("rb_zjit_class_initialized_p") .allowlist_function("rb_zjit_class_has_default_allocator") + .allowlist_function("rb_zjit_class_get_alloc_func") .allowlist_function("rb_get_ec_cfp") .allowlist_function("rb_get_cfp_iseq") .allowlist_function("rb_get_cfp_pc") diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 0b236d0b57f4ef..03228db0bb7c01 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -1314,9 +1314,16 @@ fn gen_object_alloc_class(asm: &mut Assembler, class: VALUE, state: &FrameState) // Allocating an object for a known class with default allocator is leaf; see doc for // `ObjectAllocClass`. gen_prepare_leaf_call_with_gc(asm, state); - assert!(unsafe { rb_zjit_class_has_default_allocator(class) }, "class must have default allocator"); - // TODO(max): inline code to allocate an instance - asm_ccall!(asm, rb_class_allocate_instance, class.into()) + if unsafe { rb_zjit_class_has_default_allocator(class) } { + // TODO(max): inline code to allocate an instance + asm_ccall!(asm, rb_class_allocate_instance, class.into()) + } else { + assert!(class_has_leaf_allocator(class), "class passed to ObjectAllocClass must have a leaf allocator"); + let alloc_func = unsafe { rb_zjit_class_get_alloc_func(class) }; + assert!(alloc_func.is_some(), "class {} passed to ObjectAllocClass must have an allocator", get_class_name(class)); + asm_comment!(asm, "call allocator for class {}", get_class_name(class)); + asm.ccall(alloc_func.unwrap() as *const u8, vec![class.into()]) + } } /// Compile code that exits from JIT code with a return value diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index 374faa6d972543..82d0582da40fd5 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -1218,6 +1218,19 @@ pub fn get_class_name(class: VALUE) -> String { }).unwrap_or_else(|| "Unknown".to_string()) } +pub fn class_has_leaf_allocator(class: VALUE) -> bool { + // empty_hash_alloc + if class == unsafe { rb_cHash } { return true; } + // empty_ary_alloc + if class == unsafe { rb_cArray } { return true; } + // empty_str_alloc + if class == unsafe { rb_cString } { return true; } + // rb_reg_s_alloc + if class == unsafe { rb_cRegexp } { return true; } + // rb_class_allocate_instance + unsafe { rb_zjit_class_has_default_allocator(class) } +} + /// Interned ID values for Ruby symbols and method names. /// See [type@crate::cruby::ID] and usages outside of ZJIT. pub(crate) mod ids { diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index dfdb6c0f2915e2..5a06d99f9ee661 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -948,6 +948,7 @@ unsafe extern "C" { recv: VALUE, ) -> *const rb_callable_method_entry_struct; pub fn rb_zjit_class_initialized_p(klass: VALUE) -> bool; + pub fn rb_zjit_class_get_alloc_func(klass: VALUE) -> rb_alloc_func_t; pub fn rb_zjit_class_has_default_allocator(klass: VALUE) -> bool; pub fn rb_iseq_encoded_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint; pub fn rb_iseq_pc_at_idx(iseq: *const rb_iseq_t, insn_idx: u32) -> *mut VALUE; diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 449646024a03a3..4750b187e01758 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -1978,8 +1978,8 @@ impl Function { if unsafe { rb_zjit_singleton_class_p(class) } { self.push_insn_id(block, insn_id); continue; } - if !unsafe { rb_zjit_class_has_default_allocator(class) } { - // Custom or NULL allocator; could run arbitrary code. + if !class_has_leaf_allocator(class) { + // Custom, known unsafe, or NULL allocator; could run arbitrary code. self.push_insn_id(block, insn_id); continue; } let replacement = self.push_insn(block, Insn::ObjectAllocClass { class, state }); @@ -8296,6 +8296,165 @@ mod opt_tests { "); } + #[test] + fn test_opt_new_object() { + eval(" + def test = Object.new + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, Object) + v34:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + PatchPoint MethodRedefined(Object@0x1008, new@0x1010, cme:0x1018) + v37:HeapObject[class_exact:Object] = ObjectAllocClass VALUE(0x1008) + PatchPoint MethodRedefined(Object@0x1008, initialize@0x1040, cme:0x1048) + v39:NilClass = CCall initialize@0x1070, v37 + CheckInterrupts + CheckInterrupts + Return v37 + "); + } + + #[test] + fn test_opt_new_basic_object() { + eval(" + def test = BasicObject.new + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, BasicObject) + v34:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + PatchPoint MethodRedefined(BasicObject@0x1008, new@0x1010, cme:0x1018) + v37:HeapObject[class_exact:BasicObject] = ObjectAllocClass VALUE(0x1008) + PatchPoint MethodRedefined(BasicObject@0x1008, initialize@0x1040, cme:0x1048) + v39:NilClass = CCall initialize@0x1070, v37 + CheckInterrupts + CheckInterrupts + Return v37 + "); + } + + #[test] + fn test_opt_new_hash() { + eval(" + def test = Hash.new + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, Hash) + v34:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + PatchPoint MethodRedefined(Hash@0x1008, new@0x1010, cme:0x1018) + v37:HashExact = ObjectAllocClass VALUE(0x1008) + v12:BasicObject = SendWithoutBlock v37, :initialize + CheckInterrupts + CheckInterrupts + Return v37 + "); + } + + #[test] + fn test_opt_new_array() { + eval(" + def test = Array.new 1 + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, Array) + v36:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + v7:Fixnum[1] = Const Value(1) + PatchPoint MethodRedefined(Array@0x1008, new@0x1010, cme:0x1018) + PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018) + v45:BasicObject = CCallVariadic new@0x1048, v36, v7 + CheckInterrupts + Return v45 + "); + } + + #[test] + fn test_opt_new_set() { + eval(" + def test = Set.new + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, Set) + v34:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + PatchPoint MethodRedefined(Set@0x1008, new@0x1010, cme:0x1018) + v10:HeapObject = ObjectAlloc v34 + PatchPoint MethodRedefined(Set@0x1008, initialize@0x1040, cme:0x1048) + v39:BasicObject = CCallVariadic initialize@0x1070, v10 + CheckInterrupts + CheckInterrupts + Return v10 + "); + } + + #[test] + fn test_opt_new_string() { + eval(" + def test = String.new + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, String) + v34:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + PatchPoint MethodRedefined(String@0x1008, new@0x1010, cme:0x1018) + PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018) + v43:BasicObject = CCallVariadic new@0x1048, v34 + CheckInterrupts + Return v43 + "); + } + + #[test] + fn test_opt_new_regexp() { + eval(" + def test = Regexp.new '' + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v0:BasicObject): + PatchPoint SingleRactorMode + PatchPoint StableConstantNames(0x1000, Regexp) + v38:Class[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v6:NilClass = Const Value(nil) + v7:StringExact[VALUE(0x1010)] = Const Value(VALUE(0x1010)) + v9:StringExact = StringCopy v7 + PatchPoint MethodRedefined(Regexp@0x1008, new@0x1018, cme:0x1020) + v41:HeapObject[class_exact:Regexp] = ObjectAllocClass VALUE(0x1008) + PatchPoint MethodRedefined(Regexp@0x1008, initialize@0x1048, cme:0x1050) + v44:BasicObject = CCallVariadic initialize@0x1078, v41, v9 + CheckInterrupts + CheckInterrupts + Return v41 + "); + } + #[test] fn test_opt_length() { eval(" From 451fe6a446f8e4510a333a128ca460992e02967c Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 15:30:41 -0400 Subject: [PATCH 20/22] ZJIT: Fix opt_{hash,ary,str}_{freeze,uminus} The stack layout is incompatible with the way we reify the stack for generating fallback SendWithoutBlock: the receiver is an embedded VALUE in the bytecode, not on the stack. Since we don't expect these to be overridden often, instead of fussing about with the stack layout, just hope for the best and PatchPoint/SideExit. Fix https://github.com/Shopify/ruby/issues/760 --- test/ruby/test_zjit.rb | 76 ++++++++++++-- zjit/src/hir.rs | 218 +++++++++++++++++++++++++++++------------ 2 files changed, 219 insertions(+), 75 deletions(-) diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index ea1481ca2d65c1..f383beeb3b1788 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -997,31 +997,87 @@ def test end def test_opt_hash_freeze - assert_compiles '{}', <<~RUBY, insns: [:opt_hash_freeze] + assert_compiles "[{}, 5]", %q{ + def test = {}.freeze + result = [test] + class Hash + def freeze = 5 + end + result << test + }, insns: [:opt_hash_freeze], call_threshold: 1 + end + + def test_opt_hash_freeze_rewritten + assert_compiles "5", %q{ + class Hash + def freeze = 5 + end def test = {}.freeze test - RUBY + }, insns: [:opt_hash_freeze], call_threshold: 1 end def test_opt_ary_freeze - assert_compiles '[]', <<~RUBY, insns: [:opt_ary_freeze] + assert_compiles "[[], 5]", %q{ + def test = [].freeze + result = [test] + class Array + def freeze = 5 + end + result << test + }, insns: [:opt_ary_freeze], call_threshold: 1 + end + + def test_opt_ary_freeze_rewritten + assert_compiles "5", %q{ + class Array + def freeze = 5 + end def test = [].freeze test - RUBY + }, insns: [:opt_ary_freeze], call_threshold: 1 end def test_opt_str_freeze - assert_compiles '""', <<~RUBY, insns: [:opt_str_freeze] - def test = "".freeze + assert_compiles "[\"\", 5]", %q{ + def test = ''.freeze + result = [test] + class String + def freeze = 5 + end + result << test + }, insns: [:opt_str_freeze], call_threshold: 1 + end + + def test_opt_str_freeze_rewritten + assert_compiles "5", %q{ + class String + def freeze = 5 + end + def test = ''.freeze test - RUBY + }, insns: [:opt_str_freeze], call_threshold: 1 end def test_opt_str_uminus - assert_compiles '""', <<~RUBY, insns: [:opt_str_uminus] - def test = -"" + assert_compiles "[\"\", 5]", %q{ + def test = -'' + result = [test] + class String + def -@ = 5 + end + result << test + }, insns: [:opt_str_uminus], call_threshold: 1 + end + + def test_opt_str_uminus_rewritten + assert_compiles "5", %q{ + class String + def -@ = 5 + end + def test = -'' test - RUBY + }, insns: [:opt_str_uminus], call_threshold: 1 end def test_new_array_empty diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 4750b187e01758..7305bc007d934f 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -3689,31 +3689,58 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, def_type: None, state: exit_id }); state.stack_push(send); } - YARVINSN_opt_hash_freeze | - YARVINSN_opt_ary_freeze | - YARVINSN_opt_str_freeze | - YARVINSN_opt_str_uminus => { - // NB: these instructions have the recv for the call at get_arg(0) - let cd: *const rb_call_data = get_arg(pc, 1).as_ptr(); - let call_info = unsafe { rb_get_call_data_ci(cd) }; - let flags = unsafe { rb_vm_ci_flag(call_info) }; - if let Err(call_type) = unhandled_call_type(flags) { - // Can't handle the call type; side-exit into the interpreter - let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); - fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); + YARVINSN_opt_hash_freeze => { + let klass = HASH_REDEFINED_OP_FLAG; + let bop = BOP_FREEZE; + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } { + fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id }); + let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); + state.stack_push(recv); + } else { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::PatchPoint(Invariant::BOPRedefined { klass, bop }) }); break; // End the block } - let argc = unsafe { vm_ci_argc((*cd).ci) }; - let name = insn_name(opcode as usize); - assert_eq!(0, argc, "{name} should not have args"); - let args = vec![]; - + } + YARVINSN_opt_ary_freeze => { + let klass = ARRAY_REDEFINED_OP_FLAG; + let bop = BOP_FREEZE; let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); - let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); - let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, def_type: None, state: exit_id }); - state.stack_push(send); + if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } { + fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id }); + let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); + state.stack_push(recv); + } else { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::PatchPoint(Invariant::BOPRedefined { klass, bop }) }); + break; // End the block + } + } + YARVINSN_opt_str_freeze => { + let klass = STRING_REDEFINED_OP_FLAG; + let bop = BOP_FREEZE; + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } { + fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id }); + let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); + state.stack_push(recv); + } else { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::PatchPoint(Invariant::BOPRedefined { klass, bop }) }); + break; // End the block + } + } + YARVINSN_opt_str_uminus => { + let klass = STRING_REDEFINED_OP_FLAG; + let bop = BOP_UMINUS; + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); + if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } { + fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id }); + let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); + state.stack_push(recv); + } else { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::PatchPoint(Invariant::BOPRedefined { klass, bop }) }); + break; // End the block + } } - YARVINSN_leave => { let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); fun.push_insn(block, Insn::CheckInterrupts { state: exit_id }); @@ -4790,13 +4817,29 @@ mod tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v6:BasicObject = SendWithoutBlock v5, :freeze + PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts Return v6 "); } + #[test] + fn test_opt_hash_freeze_rewritten() { + eval(" + class Hash + def freeze; 5; end + end + def test = {}.freeze + "); + assert_contains_opcode("test", YARVINSN_opt_hash_freeze); + assert_snapshot!(hir_string("test"), @r" + fn test@:5: + bb0(v0:BasicObject): + SideExit PatchPoint(BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE)) + "); + } + #[test] fn test_opt_ary_freeze() { eval(" @@ -4806,13 +4849,29 @@ mod tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v6:BasicObject = SendWithoutBlock v5, :freeze + PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts Return v6 "); } + #[test] + fn test_opt_ary_freeze_rewritten() { + eval(" + class Array + def freeze; 5; end + end + def test = [].freeze + "); + assert_contains_opcode("test", YARVINSN_opt_ary_freeze); + assert_snapshot!(hir_string("test"), @r" + fn test@:5: + bb0(v0:BasicObject): + SideExit PatchPoint(BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE)) + "); + } + #[test] fn test_opt_str_freeze() { eval(" @@ -4822,13 +4881,29 @@ mod tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v6:BasicObject = SendWithoutBlock v5, :freeze + PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts Return v6 "); } + #[test] + fn test_opt_str_freeze_rewritten() { + eval(" + class String + def freeze; 5; end + end + def test = ''.freeze + "); + assert_contains_opcode("test", YARVINSN_opt_str_freeze); + assert_snapshot!(hir_string("test"), @r" + fn test@:5: + bb0(v0:BasicObject): + SideExit PatchPoint(BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE)) + "); + } + #[test] fn test_opt_str_uminus() { eval(" @@ -4838,13 +4913,29 @@ mod tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v6:BasicObject = SendWithoutBlock v5, :-@ + PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts Return v6 "); } + #[test] + fn test_opt_str_uminus_rewritten() { + eval(" + class String + def -@; 5; end + end + def test = -'' + "); + assert_contains_opcode("test", YARVINSN_opt_str_uminus); + assert_snapshot!(hir_string("test"), @r" + fn test@:5: + bb0(v0:BasicObject): + SideExit PatchPoint(BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS)) + "); + } + #[test] fn test_setlocal_getlocal() { eval(" @@ -7324,11 +7415,11 @@ mod opt_tests { fn test@:3: bb0(v0:BasicObject): v1:NilClass = Const Value(nil) - v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) + v7:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v8:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) v10:StringExact = StringCopy v8 - v12:RangeExact = NewRange v6 NewRangeInclusive v10 + v12:RangeExact = NewRange v7 NewRangeInclusive v10 PatchPoint NoEPEscape(test) v17:Fixnum[0] = Const Value(0) CheckInterrupts @@ -8542,10 +8633,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts - Return v5 + Return v6 "); } @@ -8560,10 +8651,7 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:5: bb0(v0:BasicObject): - v5:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v6:BasicObject = SendWithoutBlock v5, :freeze - CheckInterrupts - Return v6 + SideExit PatchPoint(BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE)) "); } @@ -8575,11 +8663,11 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) CheckInterrupts - Return v5 + Return v6 "); } @@ -8623,10 +8711,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts - Return v5 + Return v6 "); } @@ -8638,11 +8726,11 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) CheckInterrupts - Return v5 + Return v6 "); } @@ -8686,10 +8774,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts - Return v5 + Return v6 "); } @@ -8701,11 +8789,11 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) CheckInterrupts - Return v5 + Return v6 "); } @@ -8751,10 +8839,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) CheckInterrupts - Return v5 + Return v6 "); } @@ -8766,11 +8854,11 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) CheckInterrupts - Return v5 + Return v6 "); } @@ -8941,13 +9029,13 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v7:Fixnum[1] = Const Value(1) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_AREF) - v19:Fixnum[5] = Const Value(5) + v18:Fixnum[5] = Const Value(5) CheckInterrupts - Return v19 + Return v18 "); } @@ -8959,13 +9047,13 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v7:Fixnum[-3] = Const Value(-3) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_AREF) - v19:Fixnum[4] = Const Value(4) + v18:Fixnum[4] = Const Value(4) CheckInterrupts - Return v19 + Return v18 "); } @@ -8977,13 +9065,13 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v7:Fixnum[-10] = Const Value(-10) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_AREF) - v19:NilClass = Const Value(nil) + v18:NilClass = Const Value(nil) CheckInterrupts - Return v19 + Return v18 "); } @@ -8995,13 +9083,13 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:2: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v7:Fixnum[10] = Const Value(10) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_AREF) - v19:NilClass = Const Value(nil) + v18:NilClass = Const Value(nil) CheckInterrupts - Return v19 + Return v18 "); } @@ -9016,10 +9104,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:5: bb0(v0:BasicObject): - v5:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v6:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) v7:Fixnum[10] = Const Value(10) - v11:BasicObject = SendWithoutBlock v5, :[], v7 + v11:BasicObject = SendWithoutBlock v6, :[], v7 CheckInterrupts Return v11 "); From d1c845e41a46c4c91c0c8cc51ad8491b7e99a7a4 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 11:52:53 -0400 Subject: [PATCH 21/22] ZJIT: Also run CI without HIR optimizer Fixes https://github.com/Shopify/ruby/issues/758 --- .github/workflows/zjit-macos.yml | 6 ++++++ .github/workflows/zjit-ubuntu.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index b97f7b4118313f..042c59a4044c80 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -38,6 +38,12 @@ jobs: specopts: '-T --zjit-call-threshold=1' test_all_opts: '--seed=46450' + - test_task: 'check' + configure: '--enable-zjit=dev' + run_opts: '--zjit-call-threshold=1 --zjit-disable-hir-opt' + specopts: '-T --zjit-call-threshold=1 -T --zjit-disable-hir-opt' + test_all_opts: '--seed=46450' + - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb configure: '--enable-yjit=dev --enable-zjit' rust_version: "1.85.0" diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index 50fea0287653f0..94cc6d8c3b5b80 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -57,6 +57,12 @@ jobs: specopts: '-T --zjit-call-threshold=1' test_all_opts: '--seed=39471' + - test_task: 'check' + configure: '--enable-zjit=dev' + run_opts: '--zjit-call-threshold=1 --zjit-disable-hir-opt' + specopts: '-T --zjit-call-threshold=1 -T --zjit-disable-hir-opt' + test_all_opts: '--seed=39471' + - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb configure: '--enable-yjit --enable-zjit=dev' rust_version: '1.85.0' From 8d1c45978329bced97c003d9612b55f578c40a65 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 19 Sep 2025 22:01:49 -0400 Subject: [PATCH 22/22] ZJIT: Move CI configure below run_opts and specopts --- .github/workflows/zjit-macos.yml | 4 ++-- .github/workflows/zjit-ubuntu.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 042c59a4044c80..4262cc87b9cfec 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -33,15 +33,15 @@ jobs: matrix: include: - test_task: 'check' - configure: '--enable-zjit=dev' run_opts: '--zjit-call-threshold=1' specopts: '-T --zjit-call-threshold=1' + configure: '--enable-zjit=dev' test_all_opts: '--seed=46450' - test_task: 'check' - configure: '--enable-zjit=dev' run_opts: '--zjit-call-threshold=1 --zjit-disable-hir-opt' specopts: '-T --zjit-call-threshold=1 -T --zjit-disable-hir-opt' + configure: '--enable-zjit=dev' test_all_opts: '--seed=46450' - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index 94cc6d8c3b5b80..5dbe9ec52449c8 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -52,15 +52,15 @@ jobs: matrix: include: - test_task: 'check' - configure: '--enable-zjit=dev' run_opts: '--zjit-call-threshold=1' specopts: '-T --zjit-call-threshold=1' + configure: '--enable-zjit=dev' test_all_opts: '--seed=39471' - test_task: 'check' - configure: '--enable-zjit=dev' run_opts: '--zjit-call-threshold=1 --zjit-disable-hir-opt' specopts: '-T --zjit-call-threshold=1 -T --zjit-disable-hir-opt' + configure: '--enable-zjit=dev' test_all_opts: '--seed=39471' - test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb