ruby-changes:68594
From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:10:20 +0900 (JST)
Subject: [ruby-changes:68594] 3d87eadf16 (master): Refactor ujit_examples.h generator. Remove dwarfdump dependency
https://git.ruby-lang.org/ruby.git/commit/?id=3d87eadf16 From 3d87eadf16a086d2f3bec0b556760c0ebfe1e7cd Mon Sep 17 00:00:00 2001 From: Alan Wu <XrXr@u...> Date: Wed, 23 Sep 2020 03:02:01 -0400 Subject: Refactor ujit_examples.h generator. Remove dwarfdump dependency --- common.mk | 8 +- gen_ujit_examples.rb | 110 ------------------ template/Makefile.in | 4 +- tool/ruby_vm/models/instructions.rb | 63 +---------- tool/ruby_vm/models/micro_jit.rb | 125 +++++++++++++++++++++ .../models/micro_jit/example_instructions.rb | 71 ++++++++++++ tool/ruby_vm/views/ujit_examples.inc.erb | 16 +++ tool/ruby_vm/views/vm.inc.erb | 2 +- ujit_compile.c | 4 +- 9 files changed, 223 insertions(+), 180 deletions(-) delete mode 100644 gen_ujit_examples.rb create mode 100644 tool/ruby_vm/models/micro_jit.rb create mode 100644 tool/ruby_vm/models/micro_jit/example_instructions.rb create mode 100644 tool/ruby_vm/views/ujit_examples.inc.erb diff --git a/common.mk b/common.mk index e32038b851..1dc7525b92 100644 --- a/common.mk +++ b/common.mk @@ -1104,13 +1104,11 @@ incs: $(INSNS) {$(VPATH)}node_name.inc {$(VPATH)}known_errors.inc \ https://github.com/ruby/ruby/blob/trunk/common.mk#L1104 {$(VPATH)}vm_call_iseq_optimized.inc $(srcdir)/revision.h \ $(REVISION_H) \ $(UNICODE_DATA_HEADERS) $(ENC_HEADERS) \ - {$(VPATH)}id.h {$(VPATH)}probes.dmyh {$(VPATH)}ujit_examples.h + {$(VPATH)}id.h {$(VPATH)}probes.dmyh insns: $(INSNS) -ujit_examples.h: gen_ujit_examples.rb vm.$(OBJEXT) - $(ECHO) generating $@ - $(Q) $(BASERUBY) $(srcdir)/gen_ujit_examples.rb +ujit_examples.inc: vm.$(OBJEXT) id.h: $(tooldir)/generic_erb.rb $(srcdir)/template/id.h.tmpl $(srcdir)/defs/id.def $(ECHO) generating $@ @@ -15040,7 +15038,7 @@ transient_heap.$(OBJEXT): {$(VPATH)}vm_core.h https://github.com/ruby/ruby/blob/trunk/common.mk#L15038 transient_heap.$(OBJEXT): {$(VPATH)}vm_debug.h transient_heap.$(OBJEXT): {$(VPATH)}vm_opts.h transient_heap.$(OBJEXT): {$(VPATH)}vm_sync.h -ujit_compile.$(OBJEXT): {$(VPATH)}ujit_examples.h +ujit_compile.$(OBJEXT): {$(VPATH)}ujit_examples.inc util.$(OBJEXT): $(hdrdir)/ruby.h util.$(OBJEXT): $(hdrdir)/ruby/ruby.h util.$(OBJEXT): $(top_srcdir)/internal/compilers.h diff --git a/gen_ujit_examples.rb b/gen_ujit_examples.rb deleted file mode 100644 index dc400bc920..0000000000 --- a/gen_ujit_examples.rb +++ /dev/null @@ -1,110 +0,0 @@ https://github.com/ruby/ruby/blob/trunk/common.mk#L0 -def get_example_instruction_id - # TODO we could get this from the script that generates vm.inc instead of doing this song and dance - `dwarfdump --name='YARVINSN_ujit_call_example' vm.o`.each_line do |line| - if (id = line[/DW_AT_const_value\s\((\d+\))/, 1]) - p [__method__, line] if $DEBUG - return id.to_i - end - end - raise -end - -def get_fileoff - # use the load command to figure out the offset to the start of the content of vm.o - `otool -l vm.o`.each_line do |line| - if (fileoff = line[/fileoff (\d+)/, 1]) - p [__method__, line] if $DEBUG - return fileoff.to_i - end - end - raise -end - -def get_symbol_offset(symbol) - `nm vm.o`.each_line do |line| - if (offset = line[Regexp.compile('(\h+).+' + Regexp.escape(symbol) + '\Z'), 1]) - p [__method__, line] if $DEBUG - return Integer(offset, 16) - end - end - raise -end - -def readint8b(offset) - bytes = IO.binread('vm.o', 8, offset) - bytes.unpack('q').first # this is native endian but we want little endian. it's fine if the host moachine is x86 -end - - -def disassemble(offset) - command = "objdump --x86-asm-syntax=intel --start-address=#{offset} --stop-address=#{offset+50} -d vm.o" - puts "Running: #{command}" - puts "feel free to verify with --reloc" - disassembly = `#{command}` - instructions = [] - puts disassembly if $DEBUG - disassembly.each_line do |line| - line = line.strip - match_data = /\h+: ((?:\h\h\s?)+)\s+(\w+)/.match(line) - if match_data - bytes = match_data[1] - mnemonic = match_data[2] - instructions << [bytes, mnemonic, line] - break if mnemonic == 'jmp' - elsif !instructions.empty? - p line - raise "expected a continuous sequence of disassembly lines" - end - end - - jmp_idx = instructions.find_index { |_, mnemonic, _| mnemonic == 'jmp' } - raise 'failed to find jmp' unless jmp_idx - raise 'generated code for example too long' unless jmp_idx < 10 - handler_instructions = instructions[(0..jmp_idx)] - - puts "Disassembly for the example handler:" - puts handler_instructions.map {|_, _, line| line} - - - raise 'rip reference in example makes copying unsafe' if handler_instructions.any? { |_, _, full_line| full_line.downcase.include?('rip') } - acceptable_mnemonics = %w(mov jmp lea call) - unrecognized = nil - handler_instructions.each { |i| unrecognized = i unless acceptable_mnemonics.include?(i[1]) } - raise "found an unrecognized \"#{unrecognized[1]}\" instruction in the example. List of recognized instructions: #{acceptable_mnemonics.join(', ')}" if unrecognized - raise 'found multiple jmp instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'jmp' } > 1 - raise "the jmp instruction seems to be relative which isn't copiable" if instructions[jmp_idx][0].split.size > 4 - raise 'found multiple call instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'call' } > 1 - call_idx = handler_instructions.find_index { |_, mnemonic, _| mnemonic == 'call' } - - - pre_call_bytes = [] - post_call_bytes = [] - handler_instructions.take(call_idx).each do |bytes, mnemonic, _| - pre_call_bytes += bytes.split - end - handler_instructions[call_idx + 1, handler_instructions.size].each do |bytes, _, _| - post_call_bytes += bytes.split - end - - File.write("ujit_examples.h", <<-EOF) -static const uint8_t ujit_pre_call_bytes[] = { #{pre_call_bytes.map{ |byte| '0x'+byte}.join(', ')} }; -static const uint8_t ujit_post_call_bytes[] = { #{post_call_bytes.map{ |byte| '0x'+byte}.join(', ')} }; - EOF - if $DEBUG - puts "file:" - puts File.binread("ujit_examples.h") - end -end - -instruction_id = get_example_instruction_id -fileoff = get_fileoff -tc_table_offset = get_symbol_offset('vm_exec_core.insns_address_table') -vm_exec_core_offset = get_symbol_offset('vm_exec_core') -p instruction_id if $DEBUG -p fileoff if $DEBUG -p tc_table_offset.to_s(16) if $DEBUG -offset_to_insn_in_tc_table = fileoff + tc_table_offset + 8 * instruction_id -p offset_to_insn_in_tc_table if $DEBUG -offset_to_handler_code_from_vm_exec_core = readint8b(offset_to_insn_in_tc_table) -p offset_to_handler_code_from_vm_exec_core if $DEBUG -disassemble(vm_exec_core_offset + offset_to_handler_code_from_vm_exec_core) diff --git a/template/Makefile.in b/template/Makefile.in index b0e987bba0..557c9922f2 100644 --- a/template/Makefile.in +++ b/template/Makefile.in @@ -590,7 +590,7 @@ update-known-errors: https://github.com/ruby/ruby/blob/trunk/template/Makefile.in#L590 $(IFCHANGE) $(srcdir)/defs/known_errors.def - INSNS = opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \ - vmtc.inc vm.inc mjit_compile.inc + vmtc.inc vm.inc mjit_compile.inc ujit_examples.inc $(INSNS): $(srcdir)/insns.def vm_opts.h \ $(srcdir)/defs/opt_operand.def $(srcdir)/defs/opt_insn_unif.def \ @@ -610,6 +610,8 @@ $(INSNS): $(srcdir)/insns.def vm_opts.h \ https://github.com/ruby/ruby/blob/trunk/template/Makefile.in#L610 $(tooldir)/ruby_vm/models/instructions_unifications.rb \ $(tooldir)/ruby_vm/models/operands_unifications.rb \ $(tooldir)/ruby_vm/models/trace_instructions.rb \ + $(tooldir)/ruby_vm/models/micro_jit.rb \ + $(tooldir)/ruby_vm/models/micro_jit/example_instructions.rb \ $(tooldir)/ruby_vm/models/typemap.rb \ $(tooldir)/ruby_vm/scripts/converter.rb \ $(tooldir)/ruby_vm/scripts/insns2vm.rb \ diff --git a/tool/ruby_vm/models/instructions.rb b/tool/ruby_vm/models/instructions.rb index 83dff9c5b0..065ac7dbf2 100644 --- a/tool/ruby_vm/models/instructions.rb +++ b/tool/ruby_vm/models/instructions.rb @@ -13,71 +13,12 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/instructions.rb#L13 require_relative 'bare_instructions' require_relative 'operands_unifications' require_relative 'instructions_unifications' - -class RubyVM::UJITExampleInstructions - include RubyVM::CEscape - - attr_reader :name - - def initialize name - @name = name - end - - def pretty_name - return sprintf "%s(...)(...)(...)", @name - end - - def jump_destination - return @orig.name - end - - def bin - return sprintf "BIN(%s)", @name - end - - def width - 1 - end - - def operands_info - "" - end - - def rets - return ['...'] - end - - def pops - return ['...'] - end - - def attributes - return [] - end - - def has_attribute? *; - return false - end - - def handles_sp? - false - end - - def always_leaf? - false - end - - @all_examples = [new('ujit_call_example')] - - def self.to_a - @all_examples - end -end +require_relative 'micro_jit' RubyVM::Instructions = RubyVM::BareInstructions.to_a + \ RubyVM::OperandsUnifications.to_a + \ RubyVM::InstructionsUnifications.to_a + \ - RubyVM::UJITExampleInstructions.to_a + RubyVM::MicroJIT::ExampleInstructions.to_a diff --git a/tool/ruby_vm/models/micro_jit.rb b/tool/ruby_vm/models/micro_jit.rb new file mode 100644 index 0000000000..eee829a2e6 --- /dev/null +++ b/tool/ruby_vm/models/micro_jit.rb @@ -0,0 +1,125 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L1 +#! /your/favourite/path/to/ruby +# -*- Ruby -*- +# -*- frozen_string_literal: true; -*- +# -*- warn_indent: true; (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/