summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-03-10 13:19:05 -0800
committerTakashi Kokubun <[email protected]>2023-03-10 13:57:52 -0800
commit76808b1ee45db247ad2aad9cc950a3a3a6e888eb (patch)
tree3560cc18ab1c0c3071ccc4c27c892ab9a6911fdc
parent6440d159b31feb495cacb279b204cdb6b54e721f (diff)
RJIT: Start testing Assembler
-rw-r--r--lib/ruby_vm/rjit/code_block.rb15
-rw-r--r--rjit_c.rb10
-rw-r--r--test/ruby/rjit/test_assembler.rb66
3 files changed, 84 insertions, 7 deletions
diff --git a/lib/ruby_vm/rjit/code_block.rb b/lib/ruby_vm/rjit/code_block.rb
index 33b96334b6..196e42d6a8 100644
--- a/lib/ruby_vm/rjit/code_block.rb
+++ b/lib/ruby_vm/rjit/code_block.rb
@@ -58,19 +58,20 @@ module RubyVM::RJIT
(@mem_block...(@mem_block + @mem_size)).include?(addr)
end
- private
-
- def dump_disasm(from, to)
+ def dump_disasm(from, to, io: STDOUT, color: true)
C.dump_disasm(from, to).each do |address, mnemonic, op_str|
@comments.fetch(address, []).each do |comment|
- puts colorize(" # #{comment}", bold: true)
+ io.puts colorize(" # #{comment}", bold: true, color:)
end
- puts colorize(" 0x#{format("%x", address)}: #{mnemonic} #{op_str}")
+ io.puts colorize(" 0x#{format("%x", address)}: #{mnemonic} #{op_str}", color:)
end
- puts
+ io.puts
end
- def colorize(text, bold: false)
+ private
+
+ def colorize(text, bold: false, color:)
+ return text unless color
buf = +''
buf << "\e[1m" if bold
buf << "\e[34m" if @outlined
diff --git a/rjit_c.rb b/rjit_c.rb
index 6f5017a3ea..7b69d043bd 100644
--- a/rjit_c.rb
+++ b/rjit_c.rb
@@ -474,6 +474,16 @@ module RubyVM::RJIT # :nodoc: all
Primitive.cexpr! '(VALUE)NUM2PTR(value)'
end
+ def HAVE_LIBCAPSTONE
+ Primitive.cstmt! %{
+ #ifdef HAVE_LIBCAPSTONE
+ return Qtrue;
+ #else
+ return Qfalse;
+ #endif
+ }
+ end
+
#
# Utilities: Not used by RJIT, but useful for debugging
#
diff --git a/test/ruby/rjit/test_assembler.rb b/test/ruby/rjit/test_assembler.rb
new file mode 100644
index 0000000000..12d73b2410
--- /dev/null
+++ b/test/ruby/rjit/test_assembler.rb
@@ -0,0 +1,66 @@
+require 'test/unit'
+require_relative '../../lib/jit_support'
+
+return unless JITSupport.rjit_supported?
+return unless RubyVM::RJIT.enabled?
+return unless RubyVM::RJIT::C.HAVE_LIBCAPSTONE
+
+require 'stringio'
+require 'ruby_vm/rjit/assembler'
+
+module RubyVM::RJIT
+ class TestAssembler < Test::Unit::TestCase
+ MEM_SIZE = 16 * 1024
+
+ def setup
+ @mem_block ||= C.mmap(MEM_SIZE)
+ @cb = CodeBlock.new(mem_block: @mem_block, mem_size: MEM_SIZE)
+ end
+
+ def test_add
+ asm = Assembler.new
+ asm.add(:rax, 255)
+ assert_compile(asm, '0x0: add rax, 0xff')
+ end
+
+ def test_jmp
+ asm = Assembler.new
+ label = asm.new_label('label')
+ asm.jmp(label)
+ asm.write_label(label)
+ asm.jmp(label)
+ assert_compile(asm, <<~EOS)
+ 0x0: jmp 0x2
+ 0x2: jmp 0x2
+ EOS
+ end
+
+ private
+
+ def assert_compile(asm, expected)
+ actual = compile(asm)
+ assert_equal expected, actual, "---\n#{actual}---"
+ end
+
+ def compile(asm)
+ start_addr = @cb.write_addr
+ @cb.write(asm)
+ end_addr = @cb.write_addr
+
+ io = StringIO.new
+ @cb.dump_disasm(start_addr, end_addr, io:, color: false)
+ io.seek(0)
+ disasm = io.read
+
+ disasm.gsub!(/^ /, '')
+ disasm.sub!(/\n\z/, '')
+ if disasm.lines.size == 1
+ disasm.rstrip!
+ end
+ (start_addr...end_addr).each do |addr|
+ disasm.gsub!("0x#{addr.to_s(16)}", "0x#{(addr - start_addr).to_s(16)}")
+ end
+ disasm
+ end
+ end
+end