From f11765aef0cafb6fadf98216c94507f2390a0a70 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 17 Oct 2022 10:47:22 -0700 Subject: [PATCH] YJIT: Allow --yjit-dump-disasm to dump into a file (#6552) * YJIT: Allow --yjit-dump-disasm to dump into a file * YJIT: Move IO implementation to disasm.rs * YJIT: More consistent naming --- yjit/src/backend/ir.rs | 11 ++++------- yjit/src/codegen.rs | 4 ++-- yjit/src/disasm.rs | 22 ++++++++++++++++++++-- yjit/src/options.rs | 32 ++++++++++++++------------------ 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index e11235aec964b4..df0600b2fff70c 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -1100,13 +1100,10 @@ impl Assembler let gc_offsets = self.compile_with_regs(cb, alloc_regs); #[cfg(feature = "disasm")] - if get_option!(dump_disasm) == DumpDisasm::All || (get_option!(dump_disasm) == DumpDisasm::Inline && cb.inline()) { - use crate::disasm::disasm_addr_range; - let last_ptr = cb.get_write_ptr(); - let disasm = disasm_addr_range(cb, start_addr, last_ptr.raw_ptr() as usize - start_addr as usize); - if disasm.len() > 0 { - println!("{disasm}"); - } + if let Some(dump_disasm) = get_option_ref!(dump_disasm) { + use crate::disasm::dump_disasm_addr_range; + let end_addr = cb.get_write_ptr().raw_ptr(); + dump_disasm_addr_range(cb, start_addr, end_addr, dump_disasm) } gc_offsets } diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 626916b24086b3..ae01149081789f 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -612,7 +612,7 @@ pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> O let code_ptr = cb.get_write_ptr(); let mut asm = Assembler::new(); - if get_option!(dump_disasm).is_enabled() { + if get_option_ref!(dump_disasm).is_some() { asm.comment(&format!("YJIT entry: {}", iseq_get_location(iseq))); } else { asm.comment("YJIT entry"); @@ -742,7 +742,7 @@ pub fn gen_single_block( let mut asm = Assembler::new(); #[cfg(feature = "disasm")] - if get_option!(dump_disasm).is_enabled() { + if get_option_ref!(dump_disasm).is_some() { asm.comment(&format!("Block: {} (ISEQ offset: {})", iseq_get_location(blockid.iseq), blockid.idx)); } diff --git a/yjit/src/disasm.rs b/yjit/src/disasm.rs index 9e45dffd60e834..21ab6b5507e9be 100644 --- a/yjit/src/disasm.rs +++ b/yjit/src/disasm.rs @@ -2,6 +2,7 @@ use crate::core::*; use crate::cruby::*; use crate::yjit::yjit_enabled_p; use crate::asm::CodeBlock; +use crate::options::DumpDisasm; use std::fmt::Write; @@ -95,7 +96,7 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St writeln!(out, "== {:=<60}", block_ident).unwrap(); // Disassemble the instructions - out.push_str(&disasm_addr_range(global_cb, start_addr, code_size)); + out.push_str(&disasm_addr_range(global_cb, start_addr, (start_addr as usize + code_size) as *const u8)); // If this is not the last block if block_idx < block_list.len() - 1 { @@ -115,9 +116,25 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St return out; } +#[cfg(feature = "disasm")] +pub fn dump_disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, end_addr: *const u8, dump_disasm: &DumpDisasm) { + use std::fs::File; + use std::io::Write; + + let disasm = disasm_addr_range(cb, start_addr, end_addr); + if disasm.len() > 0 { + match dump_disasm { + DumpDisasm::Stdout => println!("{disasm}"), + DumpDisasm::File(path) => { + let mut f = File::options().append(true).create(true).open(path).unwrap(); + f.write_all(disasm.as_bytes()).unwrap(); + } + }; + } +} #[cfg(feature = "disasm")] -pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, code_size: usize) -> String { +pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, end_addr: *const u8) -> String { let mut out = String::from(""); // Initialize capstone @@ -141,6 +158,7 @@ pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, code_size: usize cs.set_skipdata(true).unwrap(); // Disassemble the instructions + let code_size = end_addr as usize - start_addr as usize; let code_slice = unsafe { std::slice::from_raw_parts(start_addr, code_size) }; let insns = cs.disasm_all(code_slice, start_addr as u64).unwrap(); diff --git a/yjit/src/options.rs b/yjit/src/options.rs index d2b43ecb262401..303ae4980f5fbb 100644 --- a/yjit/src/options.rs +++ b/yjit/src/options.rs @@ -36,7 +36,7 @@ pub struct Options { pub dump_insns: bool, /// Dump all compiled instructions of target cbs. - pub dump_disasm: DumpDisasm, + pub dump_disasm: Option, /// Print when specific ISEQ items are compiled or invalidated pub dump_iseq_disasm: Option, @@ -62,26 +62,18 @@ pub static mut OPTIONS: Options = Options { gen_stats: false, gen_trace_exits: false, dump_insns: false, - dump_disasm: DumpDisasm::None, + dump_disasm: None, verify_ctx: false, global_constant_state: false, dump_iseq_disasm: None, }; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum DumpDisasm { - // Dump only inline cb - Inline, - // Dump both inline and outlined cbs - All, - // Dont dump anything - None, -} - -impl DumpDisasm { - pub fn is_enabled(&self) -> bool { - *self != DumpDisasm::None - } + // Dump to stdout + Stdout, + // Dump to "yjit_{pid}.log" file under the specified directory + File(String), } /// Macro to get an option value by name @@ -168,9 +160,13 @@ pub fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> { }, ("dump-disasm", _) => match opt_val.to_string().as_str() { - "all" => unsafe { OPTIONS.dump_disasm = DumpDisasm::All }, - "" => unsafe { OPTIONS.dump_disasm = DumpDisasm::Inline }, - _ => return None, + "" => unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::Stdout) }, + directory => { + let pid = std::process::id(); + let path = format!("{directory}/yjit_{pid}.log"); + println!("YJIT disasm dump: {path}"); + unsafe { OPTIONS.dump_disasm = Some(DumpDisasm::File(path)) } + } }, ("dump-iseq-disasm", _) => unsafe {