From 4fe5efbf7f784803f8ac48824f350b6dc91d644c Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 26 Dec 2022 22:06:43 -0800 Subject: [PATCH] Implement asm comments --- lib/mjit/insn_compiler.rb | 4 ++-- lib/mjit/x86_assembler.rb | 9 ++++++++- lib/ruby_vm/mjit/compiler.rb | 27 +++++++++++++++++++++++++-- mjit_c.rb | 2 +- tool/mjit/bindgen.rb | 1 - 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/mjit/insn_compiler.rb b/lib/mjit/insn_compiler.rb index 8fd8dfcef8dfdb..9c3e2f2a95dc05 100644 --- a/lib/mjit/insn_compiler.rb +++ b/lib/mjit/insn_compiler.rb @@ -19,14 +19,14 @@ def putnil(jit, ctx, asm) def leave(jit, ctx, asm) assert_eq!(ctx.stack_size, 1) - # Check interrupts + asm.comment("RUBY_VM_CHECK_INTS(ec)") asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)]) asm.test(:eax, :eax) asm.jz(not_interrupted = asm.new_label(:not_interrupted)) Compiler.compile_exit(jit, ctx, asm) # TODO: use ocb asm.write_label(not_interrupted) - # Pop the current frame (ec->cfp++) + asm.comment("pop stack frame") asm.add(CFP, C.rb_control_frame_t.size) # cfp = cfp + 1 asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], CFP) # ec->cfp = cfp diff --git a/lib/mjit/x86_assembler.rb b/lib/mjit/x86_assembler.rb index 1d010411db3591..ad194185aecc84 100644 --- a/lib/mjit/x86_assembler.rb +++ b/lib/mjit/x86_assembler.rb @@ -10,10 +10,13 @@ class Label < Data.define(:id, :name); end # REX = 0100WR0B REX_W = 0b01001000 + attr_reader :comments + def initialize @bytes = [] - @label_id = 0 @labels = {} + @label_id = 0 + @comments = Hash.new { |h, k| h[k] = [] } end def compile(addr) @@ -173,6 +176,10 @@ def test(left, right) end end + def comment(message) + @comments[@bytes.size] << message + end + def new_label(name) Label.new(id: @label_id += 1, name:) end diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb index 6641c749b66443..50da0f6fff0bad 100644 --- a/lib/ruby_vm/mjit/compiler.rb +++ b/lib/ruby_vm/mjit/compiler.rb @@ -26,11 +26,13 @@ class Compiler # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::X86Assembler] def self.compile_exit(jit, ctx, asm) - # update pc + asm.comment("exit to interpreter") + + # Update pc asm.mov(:rax, jit.pc) # rax = jit.pc asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax - # update sp + # Update sp if ctx.stack_size > 0 asm.add(SP, C.VALUE.size * ctx.stack_size) # rbx += stack_size asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) # cfp->sp = rbx @@ -45,6 +47,7 @@ def self.compile_exit(jit, ctx, asm) # @param mem_block [Integer] JIT buffer address def initialize(mem_block) + @comments = Hash.new { |h, k| h[k] = [] } @mem_block = mem_block @write_pos = 0 @insn_compiler = InsnCompiler.new @@ -56,6 +59,7 @@ def call(iseq) return if iseq.body.param.flags.has_opt asm = X86Assembler.new + asm.comment("Block: #{iseq.body.location.label}@#{iseq.body.location.pathobj}:#{iseq.body.location.first_lineno}") compile_prologue(asm) compile_block(asm, iseq) iseq.body.jit_func = compile(asm) @@ -73,11 +77,20 @@ def write_addr def compile(asm) start_addr = write_addr + # Write machine code C.mjit_mark_writable @write_pos += asm.compile(start_addr) C.mjit_mark_executable end_addr = write_addr + + # Convert comment indexes to addresses + asm.comments.each do |index, comments| + @comments[start_addr + index] += comments + end + asm.comments.clear + + # Dump disasm if --mjit-dump-disasm if C.mjit_opts.dump_disasm && start_addr < end_addr dump_disasm(start_addr, end_addr) end @@ -92,6 +105,8 @@ def compile(asm) # # @param asm [RubyVM::MJIT::X86Assembler] def compile_prologue(asm) + asm.comment("MJIT entry") + # Save callee-saved registers used by JITed code asm.push(SP) @@ -124,6 +139,7 @@ def compile_block(asm, iseq) # @param ctx [RubyVM::MJIT::Context] # @param asm [RubyVM::MJIT::X86Assembler] def compile_insn(jit, ctx, asm, insn) + asm.comment("Insn: #{insn.name}") case insn.name when :putnil then @insn_compiler.putnil(jit, ctx, asm) when :leave then @insn_compiler.leave(jit, ctx, asm) @@ -137,9 +153,16 @@ def decode_insn(encoded) def dump_disasm(from, to) C.dump_disasm(from, to).each do |address, mnemonic, op_str| + @comments.fetch(address, []).each do |comment| + puts bold(" # #{comment}") + end puts " 0x#{"%x" % address}: #{mnemonic} #{op_str}" end puts end + + def bold(text) + "\e[1m#{text}\e[0m" + end end end diff --git a/mjit_c.rb b/mjit_c.rb index 506e15f76ec4bd..95231d96c27bf9 100644 --- a/mjit_c.rb +++ b/mjit_c.rb @@ -578,7 +578,7 @@ def C.rb_iseq_location_t pathobj: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), pathobj)"), true], base_label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), base_label)"), true], label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), label)"), true], - first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)"), true], + first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)")], node_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), node_id)")], code_location: [self.rb_code_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), code_location)")], ) diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index a966a46944a324..1854820ce09cf2 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -423,7 +423,6 @@ def push_target(target) ruby_fields: { rb_iseq_location_struct: %w[ base_label - first_lineno label pathobj ]