Initial implementation of send
This commit is contained in:
parent
d09c723975
commit
fa0b9c1c97
@ -136,6 +136,10 @@ module RubyVM::MJIT
|
|||||||
in Integer => dst_addr
|
in Integer => dst_addr
|
||||||
# E9 cd
|
# E9 cd
|
||||||
insn(opcode: 0xe9, imm: rel32(dst_addr))
|
insn(opcode: 0xe9, imm: rel32(dst_addr))
|
||||||
|
# JMP r/m64 (Mod 01: [reg]+disp8)
|
||||||
|
in [Symbol => dst_reg, Integer => dst_disp] if imm8?(dst_disp)
|
||||||
|
# FF /4
|
||||||
|
insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
|
||||||
# JMP r/m64 (Mod 11: reg)
|
# JMP r/m64 (Mod 11: reg)
|
||||||
in Symbol => dst_reg
|
in Symbol => dst_reg
|
||||||
# FF /4
|
# FF /4
|
||||||
@ -145,6 +149,17 @@ module RubyVM::MJIT
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def jne(dst)
|
||||||
|
case dst
|
||||||
|
# JNE rel32
|
||||||
|
in Integer => dst_addr
|
||||||
|
# 0F 85 cd
|
||||||
|
insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr))
|
||||||
|
else
|
||||||
|
raise NotImplementedError, "jne: not-implemented operands: #{dst.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def jnz(dst)
|
def jnz(dst)
|
||||||
case dst
|
case dst
|
||||||
# JNZ rel32
|
# JNZ rel32
|
||||||
@ -182,6 +197,23 @@ module RubyVM::MJIT
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lea(dst, src)
|
||||||
|
case [dst, src]
|
||||||
|
# LEA r64,m (Mod 01: [reg]+disp8)
|
||||||
|
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_disp]] if r64?(dst_reg) && r64?(src_reg) && imm8?(src_disp)
|
||||||
|
# REX.W + 8D /r
|
||||||
|
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
|
||||||
|
insn(
|
||||||
|
prefix: REX_W,
|
||||||
|
opcode: 0x8d,
|
||||||
|
mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
|
||||||
|
disp: src_disp,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
raise NotImplementedError, "lea: not-implemented operands: #{dst.inspect}, #{src.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def mov(dst, src)
|
def mov(dst, src)
|
||||||
case dst
|
case dst
|
||||||
in Symbol => dst_reg
|
in Symbol => dst_reg
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
class RubyVM::MJIT::BlockStub < Struct.new(
|
class RubyVM::MJIT::BlockStub < Struct.new(
|
||||||
:iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Stub target ISEQ
|
:iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Stub target ISEQ
|
||||||
:ctx, # @param [RubyVM::MJIT::Context] Stub target context
|
:ctx, # @param [RubyVM::MJIT::Context] Stub target context
|
||||||
:pc, # @param [Integer] Stub target pc
|
:pc, # @param [Integer] Stub target pc
|
||||||
:start_addr, # @param [Integer] Stub source start address to be re-generated
|
:start_addr, # @param [Integer] Stub source start address to be re-generated
|
||||||
:end_addr, # @param [Integer] Stub source end address to be re-generated
|
:end_addr, # @param [Integer] Stub source end address to be re-generated
|
||||||
|
:change_block, # @param [Proc] Recompile the source address with a new block address
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -44,6 +44,11 @@ module RubyVM::MJIT
|
|||||||
@ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true)
|
@ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true)
|
||||||
@exit_compiler = ExitCompiler.new
|
@exit_compiler = ExitCompiler.new
|
||||||
@insn_compiler = InsnCompiler.new(@ocb, @exit_compiler)
|
@insn_compiler = InsnCompiler.new(@ocb, @exit_compiler)
|
||||||
|
|
||||||
|
@leave_exit = Assembler.new.then do |asm|
|
||||||
|
@exit_compiler.compile_leave_exit(asm)
|
||||||
|
@ocb.write(asm)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Compile an ISEQ from its entry point.
|
# Compile an ISEQ from its entry point.
|
||||||
@ -86,10 +91,10 @@ module RubyVM::MJIT
|
|||||||
new_addr = @cb.write(new_asm)
|
new_addr = @cb.write(new_asm)
|
||||||
@cb.with_write_addr(block_stub.start_addr) do
|
@cb.with_write_addr(block_stub.start_addr) do
|
||||||
asm = Assembler.new
|
asm = Assembler.new
|
||||||
asm.comment('regenerate block stub')
|
block_stub.change_block.call(asm, new_addr)
|
||||||
asm.jmp(new_addr)
|
|
||||||
@cb.write(asm)
|
@cb.write(asm)
|
||||||
end
|
end
|
||||||
|
new_addr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -181,6 +186,10 @@ module RubyVM::MJIT
|
|||||||
|
|
||||||
# Load sp to a dedicated register
|
# Load sp to a dedicated register
|
||||||
asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
|
asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
|
||||||
|
|
||||||
|
# Setup cfp->jit_return
|
||||||
|
asm.mov(:rax, @leave_exit)
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param asm [RubyVM::MJIT::Assembler]
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
|
@ -24,6 +24,17 @@ module RubyVM::MJIT
|
|||||||
asm.ret
|
asm.ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @param ocb [CodeBlock]
|
||||||
|
def compile_leave_exit(asm)
|
||||||
|
# Restore callee-saved registers
|
||||||
|
asm.pop(SP)
|
||||||
|
asm.pop(EC)
|
||||||
|
asm.pop(CFP)
|
||||||
|
|
||||||
|
# :rax is written by #leave
|
||||||
|
asm.ret
|
||||||
|
end
|
||||||
|
|
||||||
# @param jit [RubyVM::MJIT::JITState]
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
# @param ctx [RubyVM::MJIT::Context]
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
# @param asm [RubyVM::MJIT::Assembler]
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
@ -44,11 +55,10 @@ module RubyVM::MJIT
|
|||||||
asm.ret
|
asm.ret
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param jit [RubyVM::MJIT::JITState]
|
|
||||||
# @param ctx [RubyVM::MJIT::Context]
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
# @param asm [RubyVM::MJIT::Assembler]
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
# @param block_stub [RubyVM::MJIT::BlockStub]
|
# @param block_stub [RubyVM::MJIT::BlockStub]
|
||||||
def compile_block_stub(jit, ctx, asm, block_stub)
|
def compile_block_stub(ctx, asm, block_stub)
|
||||||
# Call rb_mjit_block_stub_hit
|
# Call rb_mjit_block_stub_hit
|
||||||
asm.comment("block stub hit: #{block_stub.iseq.body.location.label}@#{C.rb_iseq_path(block_stub.iseq)}:#{iseq_lineno(block_stub.iseq, block_stub.pc)}")
|
asm.comment("block stub hit: #{block_stub.iseq.body.location.label}@#{C.rb_iseq_path(block_stub.iseq)}:#{iseq_lineno(block_stub.iseq, block_stub.pc)}")
|
||||||
asm.mov(:rdi, to_value(block_stub))
|
asm.mov(:rdi, to_value(block_stub))
|
||||||
@ -98,7 +108,7 @@ module RubyVM::MJIT
|
|||||||
# @param asm [RubyVM::MJIT::Assembler]
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
def save_pc_and_sp(jit, ctx, asm)
|
def save_pc_and_sp(jit, ctx, asm)
|
||||||
# Update pc (TODO: manage PC offset?)
|
# Update pc (TODO: manage PC offset?)
|
||||||
asm.comment("save pc #{'and sp' if ctx.sp_offset != 0}")
|
asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP")
|
||||||
asm.mov(:rax, jit.pc) # rax = jit.pc
|
asm.mov(:rax, jit.pc) # rax = jit.pc
|
||||||
asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ module RubyVM::MJIT
|
|||||||
@ocb = ocb
|
@ocb = ocb
|
||||||
@exit_compiler = exit_compiler
|
@exit_compiler = exit_compiler
|
||||||
@invariants = Invariants.new(ocb, exit_compiler)
|
@invariants = Invariants.new(ocb, exit_compiler)
|
||||||
freeze
|
# freeze # workaround a binding.irb issue. TODO: resurrect this
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param jit [RubyVM::MJIT::JITState]
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
@ -17,7 +17,7 @@ module RubyVM::MJIT
|
|||||||
asm.incr_counter(:mjit_insns_count)
|
asm.incr_counter(:mjit_insns_count)
|
||||||
asm.comment("Insn: #{insn.name}")
|
asm.comment("Insn: #{insn.name}")
|
||||||
|
|
||||||
# 10/101
|
# 11/101
|
||||||
case insn.name
|
case insn.name
|
||||||
# nop
|
# nop
|
||||||
# getlocal
|
# getlocal
|
||||||
@ -70,7 +70,7 @@ module RubyVM::MJIT
|
|||||||
# definemethod
|
# definemethod
|
||||||
# definesmethod
|
# definesmethod
|
||||||
# send
|
# send
|
||||||
# opt_send_without_block
|
when :opt_send_without_block then opt_send_without_block(jit, ctx, asm)
|
||||||
# objtostring
|
# objtostring
|
||||||
# opt_str_freeze
|
# opt_str_freeze
|
||||||
# opt_nil_p
|
# opt_nil_p
|
||||||
@ -217,7 +217,16 @@ module RubyVM::MJIT
|
|||||||
# definemethod
|
# definemethod
|
||||||
# definesmethod
|
# definesmethod
|
||||||
# send
|
# send
|
||||||
# opt_send_without_block
|
|
||||||
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
|
# @param cd `RubyVM::MJIT::CPointer::Struct_rb_call_data`
|
||||||
|
def opt_send_without_block(jit, ctx, asm)
|
||||||
|
cd = C.rb_call_data.new(jit.operand(0))
|
||||||
|
compile_send_general(jit, ctx, asm, cd)
|
||||||
|
end
|
||||||
|
|
||||||
# objtostring
|
# objtostring
|
||||||
# opt_str_freeze
|
# opt_str_freeze
|
||||||
# opt_nil_p
|
# opt_nil_p
|
||||||
@ -233,24 +242,23 @@ module RubyVM::MJIT
|
|||||||
def leave(jit, ctx, asm)
|
def leave(jit, ctx, asm)
|
||||||
assert_eq!(ctx.stack_size, 1)
|
assert_eq!(ctx.stack_size, 1)
|
||||||
|
|
||||||
asm.comment('RUBY_VM_CHECK_INTS(ec)')
|
compile_check_ints(jit, ctx, asm)
|
||||||
asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)])
|
|
||||||
asm.test(:eax, :eax)
|
|
||||||
asm.jnz(side_exit(jit, ctx))
|
|
||||||
|
|
||||||
asm.comment('pop stack frame')
|
asm.comment('pop stack frame')
|
||||||
asm.add(CFP, C.rb_control_frame_t.size) # cfp = cfp + 1
|
asm.lea(:rax, [CFP, C.rb_control_frame_t.size])
|
||||||
asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], CFP) # ec->cfp = cfp
|
asm.mov(CFP, :rax)
|
||||||
|
asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax)
|
||||||
|
|
||||||
# Return a value
|
# Return a value (for compile_leave_exit)
|
||||||
asm.mov(:rax, [SP])
|
asm.mov(:rax, [SP])
|
||||||
|
|
||||||
# Restore callee-saved registers
|
# Set caller's SP and push a value to its stack (for JIT)
|
||||||
asm.pop(SP)
|
asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)])
|
||||||
asm.pop(EC)
|
asm.mov([SP], :rax)
|
||||||
asm.pop(CFP)
|
|
||||||
|
# Jump to cfp->jit_return
|
||||||
|
asm.jmp([CFP, -C.rb_control_frame_t.size + C.rb_control_frame_t.offsetof(:jit_return)])
|
||||||
|
|
||||||
asm.ret
|
|
||||||
EndBlock
|
EndBlock
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -471,6 +479,161 @@ module RubyVM::MJIT
|
|||||||
# Helpers
|
# Helpers
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
|
def compile_check_ints(jit, ctx, asm)
|
||||||
|
asm.comment('RUBY_VM_CHECK_INTS(ec)')
|
||||||
|
asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)])
|
||||||
|
asm.test(:eax, :eax)
|
||||||
|
asm.jnz(side_exit(jit, ctx))
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
|
# @param ctx [RubyVM::MJIT::Context]
|
||||||
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
|
# @param cd `RubyVM::MJIT::CPointer::Struct_rb_call_data`
|
||||||
|
def compile_send_general(jit, ctx, asm, cd)
|
||||||
|
ci = cd.ci
|
||||||
|
argc = C.vm_ci_argc(ci)
|
||||||
|
mid = C.vm_ci_mid(ci)
|
||||||
|
flags = C.vm_ci_flag(ci)
|
||||||
|
|
||||||
|
if flags & C.VM_CALL_KW_SPLAT != 0
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
|
||||||
|
unless jit.at_current_insn?
|
||||||
|
defer_compilation(jit, ctx, asm)
|
||||||
|
return EndBlock
|
||||||
|
end
|
||||||
|
|
||||||
|
raise 'sp_offset != stack_size' if ctx.sp_offset != ctx.stack_size # TODO: handle this
|
||||||
|
recv_depth = argc + ((flags & C.VM_CALL_ARGS_BLOCKARG == 0) ? 0 : 1)
|
||||||
|
recv_index = ctx.stack_size - 1 - recv_depth
|
||||||
|
|
||||||
|
comptime_recv = jit.peek_at_stack(recv_depth)
|
||||||
|
comptime_recv_klass = C.rb_class_of(comptime_recv)
|
||||||
|
|
||||||
|
# Guard known class
|
||||||
|
if comptime_recv_klass.singleton_class?
|
||||||
|
asm.comment('guard known object with singleton class')
|
||||||
|
asm.mov(:rax, C.to_value(comptime_recv))
|
||||||
|
asm.cmp([SP, C.VALUE.size * recv_index], :rax)
|
||||||
|
asm.jne(side_exit(jit, ctx))
|
||||||
|
else
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
|
||||||
|
# Do method lookup
|
||||||
|
cme = C.rb_callable_method_entry(comptime_recv_klass, mid)
|
||||||
|
if cme.nil?
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
|
||||||
|
case C.METHOD_ENTRY_VISI(cme)
|
||||||
|
when C.METHOD_VISI_PUBLIC
|
||||||
|
# You can always call public methods
|
||||||
|
when C.METHOD_VISI_PRIVATE
|
||||||
|
if flags & C.VM_CALL_FCALL == 0
|
||||||
|
# VM_CALL_FCALL: Callsites without a receiver of an explicit `self` receiver
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
when C.METHOD_VISI_PROTECTED
|
||||||
|
return CantCompile # TODO: support this
|
||||||
|
else
|
||||||
|
raise 'cmes should always have a visibility'
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: assume_method_lookup_stable
|
||||||
|
|
||||||
|
if flags & C.VM_CALL_ARGS_SPLAT != 0 && cme.def.type != C.VM_METHOD_TYPE_ISEQ
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
|
||||||
|
case cme.def.type
|
||||||
|
when C.VM_METHOD_TYPE_ISEQ
|
||||||
|
iseq = def_iseq_ptr(cme.def)
|
||||||
|
frame_type = C.VM_FRAME_MAGIC_METHOD | C.VM_ENV_FLAG_LOCAL
|
||||||
|
compile_send_iseq(jit, ctx, asm, iseq, ci, frame_type, cme, flags, argc)
|
||||||
|
else
|
||||||
|
return CantCompile
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_send_iseq(jit, ctx, asm, iseq, ci, frame_type, cme, flags, argc)
|
||||||
|
# TODO: check a bunch of CantCompile cases
|
||||||
|
|
||||||
|
compile_check_ints(jit, ctx, asm)
|
||||||
|
|
||||||
|
# TODO: stack overflow check
|
||||||
|
|
||||||
|
# TODO: more flag checks
|
||||||
|
|
||||||
|
# Pop arguments and a receiver for the current caller frame
|
||||||
|
raise 'sp_offset != stack_size' if ctx.sp_offset != ctx.stack_size # TODO: handle this
|
||||||
|
sp_index = ctx.stack_size - argc - 1 # arguments and receiver
|
||||||
|
asm.comment('save SP to caller CFP')
|
||||||
|
asm.lea(:rax, [SP, sp_index])
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax)
|
||||||
|
# TODO: do something about ctx.sp_index
|
||||||
|
|
||||||
|
asm.comment('save PC to CFP')
|
||||||
|
next_pc = jit.pc + jit.insn.len * C.VALUE.size
|
||||||
|
asm.mov(:rax, next_pc)
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
|
||||||
|
|
||||||
|
# TODO: push cme, specval, frame type
|
||||||
|
# TODO: push callee control frame
|
||||||
|
|
||||||
|
asm.comment('switch to new CFP')
|
||||||
|
asm.lea(:rax, [CFP, -C.rb_control_frame_t.size])
|
||||||
|
asm.mov(CFP, :rax);
|
||||||
|
asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax)
|
||||||
|
|
||||||
|
asm.comment('save SP to callee CFP')
|
||||||
|
num_locals = 0 # TODO
|
||||||
|
sp_offset = C.VALUE.size * (3 + num_locals + ctx.stack_size)
|
||||||
|
asm.add(SP, sp_offset)
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP)
|
||||||
|
|
||||||
|
asm.comment('save ISEQ to callee CFP')
|
||||||
|
asm.mov(:rax, iseq.to_i)
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:iseq)], :rax)
|
||||||
|
|
||||||
|
asm.comment('save EP to callee CFP')
|
||||||
|
asm.lea(:rax, [SP, -C.VALUE.size])
|
||||||
|
asm.mov([CFP, C.rb_control_frame_t.offsetof(:ep)], :rax)
|
||||||
|
|
||||||
|
asm.comment('set frame type')
|
||||||
|
asm.mov([SP, C.VALUE.size * -1], C.VM_FRAME_MAGIC_METHOD | C.VM_ENV_FLAG_LOCAL)
|
||||||
|
|
||||||
|
asm.comment('set specval')
|
||||||
|
asm.mov([SP, C.VALUE.size * -2], C.VM_BLOCK_HANDLER_NONE)
|
||||||
|
|
||||||
|
# Stub the return destination from the callee
|
||||||
|
# TODO: set up return ctx correctly
|
||||||
|
jit_return_stub = BlockStub.new(iseq: jit.iseq, pc: next_pc, ctx: ctx.dup)
|
||||||
|
jit_return = Assembler.new.then do |ocb_asm|
|
||||||
|
@exit_compiler.compile_block_stub(ctx, ocb_asm, jit_return_stub)
|
||||||
|
@ocb.write(ocb_asm)
|
||||||
|
end
|
||||||
|
|
||||||
|
jit_return_stub.change_block = proc do |jump_asm, new_addr|
|
||||||
|
jump_asm.comment('update cfp->jit_return')
|
||||||
|
jump_asm.stub(jit_return_stub) do
|
||||||
|
jump_asm.mov(:rax, new_addr)
|
||||||
|
jump_asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
jit_return_stub.change_block.call(asm, jit_return)
|
||||||
|
|
||||||
|
callee_ctx = Context.new
|
||||||
|
compile_block_stub(iseq, iseq.body.iseq_encoded.to_i, callee_ctx, asm)
|
||||||
|
|
||||||
|
EndBlock
|
||||||
|
end
|
||||||
|
|
||||||
def assert_eq!(left, right)
|
def assert_eq!(left, right)
|
||||||
if left != right
|
if left != right
|
||||||
raise "'#{left.inspect}' was not '#{right.inspect}'"
|
raise "'#{left.inspect}' was not '#{right.inspect}'"
|
||||||
@ -487,21 +650,24 @@ module RubyVM::MJIT
|
|||||||
# @param asm [RubyVM::MJIT::Assembler]
|
# @param asm [RubyVM::MJIT::Assembler]
|
||||||
def defer_compilation(jit, ctx, asm)
|
def defer_compilation(jit, ctx, asm)
|
||||||
# Make a stub to compile the current insn
|
# Make a stub to compile the current insn
|
||||||
block_stub = BlockStub.new(
|
compile_block_stub(jit.iseq, jit.pc, ctx, asm, comment: 'defer_compilation: block stub')
|
||||||
iseq: jit.iseq,
|
end
|
||||||
ctx: ctx.dup,
|
|
||||||
pc: jit.pc,
|
def compile_block_stub(iseq, pc, ctx, asm, comment: 'block stub')
|
||||||
)
|
block_stub = BlockStub.new(iseq:, pc:, ctx: ctx.dup)
|
||||||
|
|
||||||
stub_hit = Assembler.new.then do |ocb_asm|
|
stub_hit = Assembler.new.then do |ocb_asm|
|
||||||
@exit_compiler.compile_block_stub(jit, ctx, ocb_asm, block_stub)
|
@exit_compiler.compile_block_stub(ctx, ocb_asm, block_stub)
|
||||||
@ocb.write(ocb_asm)
|
@ocb.write(ocb_asm)
|
||||||
end
|
end
|
||||||
|
|
||||||
asm.comment('defer_compilation: block stub')
|
block_stub.change_block = proc do |jump_asm, new_addr|
|
||||||
asm.stub(block_stub) do
|
jump_asm.comment(comment)
|
||||||
asm.jmp(stub_hit)
|
jump_asm.stub(block_stub) do
|
||||||
|
jump_asm.jmp(new_addr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
block_stub.change_block.call(asm, stub_hit)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param jit [RubyVM::MJIT::JITState]
|
# @param jit [RubyVM::MJIT::JITState]
|
||||||
@ -514,5 +680,9 @@ module RubyVM::MJIT
|
|||||||
@exit_compiler.compile_side_exit(jit, ctx, asm)
|
@exit_compiler.compile_side_exit(jit, ctx, asm)
|
||||||
jit.side_exits[jit.pc] = @ocb.write(asm)
|
jit.side_exits[jit.pc] = @ocb.write(asm)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def def_iseq_ptr(cme_def)
|
||||||
|
C.rb_iseq_check(cme_def.body.iseq.iseqptr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -20,9 +20,9 @@ module RubyVM::MJIT
|
|||||||
pc == cfp.pc.to_i
|
pc == cfp.pc.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def peek_at_stack(offset_from_top)
|
def peek_at_stack(depth_from_top)
|
||||||
raise 'not at current insn' unless at_current_insn?
|
raise 'not at current insn' unless at_current_insn?
|
||||||
offset = -(1 + offset_from_top)
|
offset = -(1 + depth_from_top)
|
||||||
value = (cfp.sp + offset).*
|
value = (cfp.sp + offset).*
|
||||||
C.to_ruby(value)
|
C.to_ruby(value)
|
||||||
end
|
end
|
||||||
|
104
mjit_c.rb
104
mjit_c.rb
@ -81,6 +81,21 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
Primitive.cexpr! 'UINT2NUM(rb_iseq_line_no((const rb_iseq_t *)NUM2SIZET(_iseq_addr), NUM2SIZET(pos)))'
|
Primitive.cexpr! 'UINT2NUM(rb_iseq_line_no((const rb_iseq_t *)NUM2SIZET(_iseq_addr), NUM2SIZET(pos)))'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rb_class_of(obj)
|
||||||
|
Primitive.cexpr! 'rb_class_of(obj)'
|
||||||
|
end
|
||||||
|
|
||||||
|
def rb_callable_method_entry(klass, mid)
|
||||||
|
cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry(klass, NUM2UINT(mid)))'
|
||||||
|
return nil if cme_addr == 0
|
||||||
|
rb_callable_method_entry_struct.new(cme_addr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def METHOD_ENTRY_VISI(cme)
|
||||||
|
_cme_addr = cme.to_i
|
||||||
|
Primitive.cexpr! 'UINT2NUM(METHOD_ENTRY_VISI((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))'
|
||||||
|
end
|
||||||
|
|
||||||
#========================================================================================
|
#========================================================================================
|
||||||
#
|
#
|
||||||
# Old stuff
|
# Old stuff
|
||||||
@ -142,6 +157,11 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))'
|
Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def vm_ci_mid(ci)
|
||||||
|
_ci_addr = ci.to_i
|
||||||
|
Primitive.cexpr! 'UINT2NUM(vm_ci_mid((CALL_INFO)NUM2PTR(_ci_addr)))'
|
||||||
|
end
|
||||||
|
|
||||||
def rb_splat_or_kwargs_p(ci)
|
def rb_splat_or_kwargs_p(ci)
|
||||||
_ci_addr = ci.to_i
|
_ci_addr = ci.to_i
|
||||||
Primitive.cstmt! %{
|
Primitive.cstmt! %{
|
||||||
@ -233,30 +253,6 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) }
|
Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def C.VM_CALL_KW_SPLAT
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.VM_CALL_KW_SPLAT_bit
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT_bit) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.VM_CALL_TAILCALL
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.VM_CALL_TAILCALL_bit
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL_bit) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.VM_METHOD_TYPE_CFUNC
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_CFUNC) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.VM_METHOD_TYPE_ISEQ
|
|
||||||
Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def C.BOP_LT
|
def C.BOP_LT
|
||||||
Primitive.cexpr! %q{ UINT2NUM(BOP_LT) }
|
Primitive.cexpr! %q{ UINT2NUM(BOP_LT) }
|
||||||
end
|
end
|
||||||
@ -269,6 +265,18 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
Primitive.cexpr! %q{ UINT2NUM(INTEGER_REDEFINED_OP_FLAG) }
|
Primitive.cexpr! %q{ UINT2NUM(INTEGER_REDEFINED_OP_FLAG) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def C.METHOD_VISI_PRIVATE
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PRIVATE) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.METHOD_VISI_PROTECTED
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PROTECTED) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.METHOD_VISI_PUBLIC
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(METHOD_VISI_PUBLIC) }
|
||||||
|
end
|
||||||
|
|
||||||
def C.RUBY_EVENT_CLASS
|
def C.RUBY_EVENT_CLASS
|
||||||
Primitive.cexpr! %q{ UINT2NUM(RUBY_EVENT_CLASS) }
|
Primitive.cexpr! %q{ UINT2NUM(RUBY_EVENT_CLASS) }
|
||||||
end
|
end
|
||||||
@ -301,6 +309,54 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
Primitive.cexpr! %q{ UINT2NUM(SHAPE_ROOT) }
|
Primitive.cexpr! %q{ UINT2NUM(SHAPE_ROOT) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def C.VM_BLOCK_HANDLER_NONE
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_BLOCK_HANDLER_NONE) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_ARGS_BLOCKARG
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_ARGS_BLOCKARG) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_ARGS_SPLAT
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_ARGS_SPLAT) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_FCALL
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_FCALL) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_KW_SPLAT
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_KW_SPLAT) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_KW_SPLAT_bit
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_KW_SPLAT_bit) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_TAILCALL
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_TAILCALL) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_CALL_TAILCALL_bit
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_CALL_TAILCALL_bit) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_ENV_FLAG_LOCAL
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_ENV_FLAG_LOCAL) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_FRAME_MAGIC_METHOD
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_FRAME_MAGIC_METHOD) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_METHOD_TYPE_CFUNC
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_METHOD_TYPE_CFUNC) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def C.VM_METHOD_TYPE_ISEQ
|
||||||
|
Primitive.cexpr! %q{ UINT2NUM(VM_METHOD_TYPE_ISEQ) }
|
||||||
|
end
|
||||||
|
|
||||||
def C.INVALID_SHAPE_ID
|
def C.INVALID_SHAPE_ID
|
||||||
Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) }
|
Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) }
|
||||||
end
|
end
|
||||||
|
@ -345,17 +345,14 @@ generator = BindingGenerator.new(
|
|||||||
values: {
|
values: {
|
||||||
INT: %w[
|
INT: %w[
|
||||||
NOT_COMPILED_STACK_SIZE
|
NOT_COMPILED_STACK_SIZE
|
||||||
VM_CALL_KW_SPLAT
|
|
||||||
VM_CALL_KW_SPLAT_bit
|
|
||||||
VM_CALL_TAILCALL
|
|
||||||
VM_CALL_TAILCALL_bit
|
|
||||||
VM_METHOD_TYPE_CFUNC
|
|
||||||
VM_METHOD_TYPE_ISEQ
|
|
||||||
],
|
],
|
||||||
UINT: %w[
|
UINT: %w[
|
||||||
BOP_LT
|
BOP_LT
|
||||||
BOP_MINUS
|
BOP_MINUS
|
||||||
INTEGER_REDEFINED_OP_FLAG
|
INTEGER_REDEFINED_OP_FLAG
|
||||||
|
METHOD_VISI_PRIVATE
|
||||||
|
METHOD_VISI_PROTECTED
|
||||||
|
METHOD_VISI_PUBLIC
|
||||||
RUBY_EVENT_CLASS
|
RUBY_EVENT_CLASS
|
||||||
SHAPE_CAPACITY_CHANGE
|
SHAPE_CAPACITY_CHANGE
|
||||||
SHAPE_FLAG_SHIFT
|
SHAPE_FLAG_SHIFT
|
||||||
@ -364,6 +361,18 @@ generator = BindingGenerator.new(
|
|||||||
SHAPE_INITIAL_CAPACITY
|
SHAPE_INITIAL_CAPACITY
|
||||||
SHAPE_IVAR
|
SHAPE_IVAR
|
||||||
SHAPE_ROOT
|
SHAPE_ROOT
|
||||||
|
VM_BLOCK_HANDLER_NONE
|
||||||
|
VM_CALL_ARGS_BLOCKARG
|
||||||
|
VM_CALL_ARGS_SPLAT
|
||||||
|
VM_CALL_FCALL
|
||||||
|
VM_CALL_KW_SPLAT
|
||||||
|
VM_CALL_KW_SPLAT_bit
|
||||||
|
VM_CALL_TAILCALL
|
||||||
|
VM_CALL_TAILCALL_bit
|
||||||
|
VM_ENV_FLAG_LOCAL
|
||||||
|
VM_FRAME_MAGIC_METHOD
|
||||||
|
VM_METHOD_TYPE_CFUNC
|
||||||
|
VM_METHOD_TYPE_ISEQ
|
||||||
],
|
],
|
||||||
ULONG: %w[
|
ULONG: %w[
|
||||||
INVALID_SHAPE_ID
|
INVALID_SHAPE_ID
|
||||||
|
Loading…
x
Reference in New Issue
Block a user