[前][次][番号順一覧][スレッド一覧]

ruby-changes:73325

From: Takashi <ko1@a...>
Date: Tue, 30 Aug 2022 01:10:23 +0900 (JST)
Subject: [ruby-changes:73325] def3ade8a8 (master): Add --yjit-dump-disasm to dump every compiled code (https://github.com/Shopify/ruby/pull/430)

https://git.ruby-lang.org/ruby.git/commit/?id=def3ade8a8

From def3ade8a809a230648cdffbf4ab066b07fe7bf1 Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Tue, 23 Aug 2022 13:46:43 -0700
Subject: Add --yjit-dump-disasm to dump every compiled code
 (https://github.com/Shopify/ruby/pull/430)

* Add --yjit-dump-disasm to dump every compiled code

* Just use get_option

* Carve out disasm_from_addr

* Avoid push_str with format!

* Share the logic through asm.compile

* This seems to negatively impact the compilation speed
---
 yjit/src/asm/mod.rs    | 10 ++++--
 yjit/src/backend/ir.rs | 19 ++++++++++--
 yjit/src/codegen.rs    | 15 +++++++--
 yjit/src/core.rs       |  1 +
 yjit/src/disasm.rs     | 82 +++++++++++++++++++++++++++++---------------------
 yjit/src/options.rs    |  5 +++
 6 files changed, 91 insertions(+), 41 deletions(-)

diff --git a/yjit/src/asm/mod.rs b/yjit/src/asm/mod.rs
index fef4518816..4029e2ca67 100644
--- a/yjit/src/asm/mod.rs
+++ b/yjit/src/asm/mod.rs
@@ -57,6 +57,10 @@ pub struct CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L57
     #[cfg(feature = "asm_comments")]
     asm_comments: BTreeMap<usize, Vec<String>>,
 
+    // True for OutlinedCb
+    #[cfg(feature = "disasm")]
+    pub outlined: bool,
+
     // Set if the CodeBlock is unable to output some instructions,
     // for example, when there is not enough space or when a jump
     // target is too far away.
@@ -65,7 +69,7 @@ pub struct CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L69
 
 impl CodeBlock {
     /// Make a new CodeBlock
-    pub fn new(mem_block: VirtualMem) -> Self {
+    pub fn new(mem_block: VirtualMem, outlined: bool) -> Self {
         Self {
             mem_size: mem_block.virtual_region_size(),
             mem_block,
@@ -75,6 +79,8 @@ impl CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L79
             label_refs: Vec::new(),
             #[cfg(feature = "asm_comments")]
             asm_comments: BTreeMap::new(),
+            #[cfg(feature = "disasm")]
+            outlined,
             dropped_bytes: false,
         }
     }
@@ -282,7 +288,7 @@ impl CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L288
         let mem_start: *const u8 = alloc.mem_start();
         let virt_mem = VirtualMem::new(alloc, 1, mem_start as *mut u8, mem_size);
 
-        Self::new(virt_mem)
+        Self::new(virt_mem, false)
     }
 }
 
diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index f01ab398da..33a79a4179 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -10,6 +10,7 @@ use crate::cruby::{VALUE}; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L10
 use crate::virtualmem::{CodePtr};
 use crate::asm::{CodeBlock, uimm_num_bits, imm_num_bits};
 use crate::core::{Context, Type, TempMapping};
+use crate::options::*;
 
 #[cfg(target_arch = "x86_64")]
 use crate::backend::x86_64::*;
@@ -1075,11 +1076,25 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L1076
     ///       compiling multiple blocks at a time?
     pub fn compile(self, cb: &mut CodeBlock) -> Vec<u32>
     {
+        #[cfg(feature = "disasm")]
+        let start_addr = cb.get_write_ptr().raw_ptr();
+
         let alloc_regs = Self::get_alloc_regs();
-        self.compile_with_regs(cb, alloc_regs)
+        let gc_offsets = self.compile_with_regs(cb, alloc_regs);
+
+        #[cfg(feature = "disasm")]
+        if get_option!(dump_disasm) && !cb.outlined {
+            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}");
+            }
+        }
+        gc_offsets
     }
 
-    /// Compile with a limited number of registers
+    /// Compile with a limited number of registers. Used only for unit tests.
     pub fn compile_with_num_regs(self, cb: &mut CodeBlock, num_regs: usize) -> Vec<u32>
     {
         let mut alloc_regs = Self::get_alloc_regs();
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 1336fe3c57..7c4c974345 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -622,9 +622,13 @@ pub fn gen_entry_prologue(cb: &mut CodeBlock, iseq: IseqPtr, insn_idx: u32) -> O https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L622
     cb.align_pos(64);
 
     let code_ptr = cb.get_write_ptr();
-    add_comment(cb, "yjit entry");
 
     let mut asm = Assembler::new();
+    if get_option!(dump_disasm) {
+        asm.comment(&format!("YJIT entry: {}", iseq_get_location(iseq)));
+    } else {
+        asm.comment("YJIT entry");
+    }
 
     asm.frame_setup();
 
@@ -748,6 +752,11 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L752
     // Create a backend assembler instance
     let mut asm = Assembler::new();
 
+    #[cfg(feature = "disasm")]
+    if get_option!(dump_disasm) {
+        asm.comment(&format!("Block: {} (ISEQ offset: {})", iseq_get_location(blockid.iseq), blockid.idx));
+    }
+
     // For each instruction to compile
     // NOTE: could rewrite this loop with a std::iter::Iterator
     while insn_idx < iseq_size {
@@ -6049,8 +6058,8 @@ impl CodegenGlobals { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L6058
                 half_size
             );
 
-            let cb = CodeBlock::new(first_half);
-            let ocb = OutlinedCb::wrap(CodeBlock::new(second_half));
+            let cb = CodeBlock::new(first_half, false);
+            let ocb = OutlinedCb::wrap(CodeBlock::new(second_half, true));
 
             (cb, ocb)
         };
diff --git a/yjit/src/core.rs b/yjit/src/core.rs
index 7d07918228..fa82dcc308 100644
--- a/yjit/src/core.rs
+++ b/yjit/src/core.rs
@@ -1510,6 +1510,7 @@ fn regenerate_branch(cb: &mut CodeBlock, branch: &mut Branch) { https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1510
     cb.set_write_ptr(branch.start_addr.unwrap());
 
     let mut asm = Assembler::new();
+    asm.comment("regenerate_branch");
 
     (branch.gen_fn)(
         &mut asm,
diff --git a/yjit/src/disasm.rs b/yjit/src/disasm.rs
index 015c0c25ef..3d1c5b33fd 100644
--- a/yjit/src/disasm.rs
+++ b/yjit/src/disasm.rs
@@ -1,6 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/disasm.rs#L1
 use crate::core::*;
 use crate::cruby::*;
 use crate::yjit::yjit_enabled_p;
+use crate::asm::CodeBlock;
+use crate::codegen::CodePtr;
+use std::fmt::Write;
 
 /// Primitive called in yjit.rb
 /// Produce a string representing the disassembly for an ISEQ
@@ -36,7 +39,7 @@ pub extern "C" fn rb_yjit_disasm_iseq(_ec: EcPtr, _ruby_self: VALUE, iseqw: VALU https://github.com/ruby/ruby/blob/trunk/yjit/src/disasm.rs#L39
 
 #[cfg(feature = "disasm")]
 pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> String {
-        let mut out = String::from("");
+    let mut out = String::from("");
 
     // Get a list of block versions generated for this iseq
     let mut block_list = get_iseq_block_list(iseq);
@@ -67,26 +70,6 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St https://github.com/ruby/ruby/blob/trunk/yjit/src/disasm.rs#L70
         total_code_size += blockref.borrow().code_size();
     }
 
-    // Initialize capstone
-    use capstone::prelude::*;
-
-    #[cfg(target_arch = "x86_64")]
-    let mut cs = Capstone::new()
-        .x86()
-        .mode(arch::x86::ArchMode::Mode64)
-        .syntax(arch::x86::ArchSyntax::Intel)
-        .build()
-        .unwrap();
-
-    #[cfg(target_arch = "aarch64")]
-    let mut cs = Capstone::new()
-        .arm64()
-        .mode(arch::arm64::ArchMode::Arm)
-        .detail(true)
-        .build()
-        .unwrap();
-    cs.set_skipdata(true);
-
     out.push_str(&format!("NUM BLOCK VERSIONS: {}\n", block_list.len()));
     out.push_str(&format!(
         "TOTAL INLINE CODE SIZE: {} bytes\n",
@@ -115,19 +98,7 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St https://github.com/ruby/ruby/blob/trunk/yjit/src/disasm.rs#L98
             out.push_str(&format!("== {:=<60}\n", block_ident));
 
             // Disassemble the instructions
-            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();
-
-            // For each instruction in this block
-            for insn in insns.as_ref() {
-                // Comments for this block
-                if let Some(comment_list) = global_cb.comments_at(insn.address() as usize) {
-                    for comment in comment_list {
-                        out.push_str(&format!("  \x1b[1m# {}\x1b[0m\n", comment));
-                    }
-                }
-                out.push_str(&format!("  {}\n", insn));
-            }
+            out.push_str(&disasm_addr_range(global_cb, start_addr, code_size));
 
             // If this is not the last block
             if block_idx < block_list.len() - 1 {
@@ -147,6 +118,49 @@ pub fn disasm_iseq_insn_range(iseq: IseqPtr, start_idx: u32, end_idx: u32) -> St https://github.com/ruby/ruby/blob/trunk/yjit/src/disasm.rs#L118
     return out;
 }
 
+
+#[cfg(feature = "disasm")]
+pub fn disasm_addr_range(cb: &CodeBlock, start_addr: *const u8, code_size: usize) -> String {
+    let mut out = String::from("");
+
+    // Initialize capstone
+    use capstone::prelude::*;
+
+    #[cfg(target_arch = "x86_64")]
+    let mut cs = Capstone::new()
+        .x86()
+        .mode(arch::x86::ArchMode::Mode64)
+        .syntax(arch::x86::ArchSyntax::Intel)
+        .build()
+        .unwrap();
+
+    #[cfg(target_arch = "aarch64")]
+    let mut cs = Capstone::new()
+        .arm64()
+        .mode(arch::arm64::ArchMode::Arm)
+        .detail(true)
+        .build()
+        .unwrap();
+    cs.set_skipdata(true);
+
+    // Disassemble the (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]