1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
class RubyVM::MJIT::Assembler
ByteWriter = RubyVM::MJIT::CType::Immediate.parse('char')
def initialize
@bytes = []
end
def compile(compiler) = with_dump_disasm(compiler) do
RubyVM::MJIT::C.mjit_mark_writable
write_bytes(compiler.write_addr, @bytes)
RubyVM::MJIT::C.mjit_mark_executable
compiler.write_pos += @bytes.size
@bytes.clear
end
def add(_reg, imm)
# REX.W [83] RSI ib
@bytes.push(0x48, 0x83, 0xc6, imm)
end
def mov(reg, val)
case reg
when :rax
# REX.W [C7] RAX imm32
@bytes.push(0x48, 0xc7, 0xc0, val, 0x00, 0x00, 0x00)
else
# REX.W [89] [rdi+val],rsi
@bytes.push(0x48, 0x89, 0x77, reg.last)
end
end
def ret
# Near return
# [C3]
@bytes.push(0xc3)
end
private
def with_dump_disasm(compiler)
from = compiler.write_addr
yield
to = compiler.write_addr
if RubyVM::MJIT::C.mjit_opts.dump_disasm && from < to
RubyVM::MJIT::C.dump_disasm(from, to).each do |address, mnemonic, op_str|
puts " 0x#{"%p" % address}: #{mnemonic} #{op_str}"
end
end
end
def write_bytes(addr, bytes)
writer = ByteWriter.new(addr)
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
# So writing byte by byte to avoid hitting that situation.
bytes.each_with_index do |byte, index|
writer[index] = byte
end
end
end
|