RJIT: Upgrade type to UnknownHeap after guard
This commit is contained in:
parent
be4e16bc1a
commit
eb51248c4c
@ -419,7 +419,7 @@ module RubyVM::RJIT
|
|||||||
id = jit.operand(0)
|
id = jit.operand(0)
|
||||||
comptime_obj = jit.peek_at_self
|
comptime_obj = jit.peek_at_self
|
||||||
|
|
||||||
jit_getivar(jit, ctx, asm, comptime_obj, id)
|
jit_getivar(jit, ctx, asm, comptime_obj, id, nil, SelfOpnd)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param jit [RubyVM::RJIT::JITState]
|
# @param jit [RubyVM::RJIT::JITState]
|
||||||
@ -481,7 +481,7 @@ module RubyVM::RJIT
|
|||||||
side_exit = side_exit(jit, ctx)
|
side_exit = side_exit(jit, ctx)
|
||||||
|
|
||||||
# Upgrade type
|
# Upgrade type
|
||||||
guard_object_is_heap(asm, :rax, counted_exit(side_exit, :setivar_not_heap))
|
guard_object_is_heap(jit, ctx, asm, :rax, SelfOpnd, :setivar_not_heap)
|
||||||
|
|
||||||
asm.comment('guard shape')
|
asm.comment('guard shape')
|
||||||
asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
|
asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
|
||||||
@ -977,10 +977,11 @@ module RubyVM::RJIT
|
|||||||
side_exit = side_exit(jit, ctx)
|
side_exit = side_exit(jit, ctx)
|
||||||
|
|
||||||
array_opnd = ctx.stack_opnd(0)
|
array_opnd = ctx.stack_opnd(0)
|
||||||
|
array_stack_opnd = StackOpnd[0]
|
||||||
|
|
||||||
# num is the number of requested values. If there aren't enough in the
|
# num is the number of requested values. If there aren't enough in the
|
||||||
# array then we're going to push on nils.
|
# array then we're going to push on nils.
|
||||||
if ctx.get_opnd_type(StackOpnd[0]) == Type::Nil
|
if ctx.get_opnd_type(array_stack_opnd) == Type::Nil
|
||||||
ctx.stack_pop(1) # pop after using the type info
|
ctx.stack_pop(1) # pop after using the type info
|
||||||
# special case for a, b = nil pattern
|
# special case for a, b = nil pattern
|
||||||
# push N nils onto the stack
|
# push N nils onto the stack
|
||||||
@ -993,7 +994,7 @@ module RubyVM::RJIT
|
|||||||
|
|
||||||
# Move the array from the stack and check that it's an array.
|
# Move the array from the stack and check that it's an array.
|
||||||
asm.mov(:rax, array_opnd)
|
asm.mov(:rax, array_opnd)
|
||||||
guard_object_is_heap(asm, :rax, counted_exit(side_exit, :expandarray_not_array))
|
guard_object_is_heap(jit, ctx, asm, :rax, array_stack_opnd, :expandarray_not_array)
|
||||||
guard_object_is_array(asm, :rax, :rcx, counted_exit(side_exit, :expandarray_not_array))
|
guard_object_is_array(asm, :rax, :rcx, counted_exit(side_exit, :expandarray_not_array))
|
||||||
ctx.stack_pop(1) # pop after using the type info
|
ctx.stack_pop(1) # pop after using the type info
|
||||||
|
|
||||||
@ -1341,7 +1342,7 @@ module RubyVM::RJIT
|
|||||||
side_exit = side_exit(jit, ctx)
|
side_exit = side_exit(jit, ctx)
|
||||||
|
|
||||||
# Guard heap object (recv_opnd must be used before stack_pop)
|
# Guard heap object (recv_opnd must be used before stack_pop)
|
||||||
guard_object_is_heap(asm, recv, side_exit)
|
guard_object_is_heap(jit, ctx, asm, recv, SelfOpnd)
|
||||||
|
|
||||||
shape_opnd = DwordPtr[recv, C.rb_shape_id_offset]
|
shape_opnd = DwordPtr[recv, C.rb_shape_id_offset]
|
||||||
|
|
||||||
@ -3445,16 +3446,30 @@ module RubyVM::RJIT
|
|||||||
local_table_size - op - 1
|
local_table_size - op - 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @param jit [RubyVM::RJIT::JITState]
|
||||||
|
# @param ctx [RubyVM::RJIT::Context]
|
||||||
# @param asm [RubyVM::RJIT::Assembler]
|
# @param asm [RubyVM::RJIT::Assembler]
|
||||||
def guard_object_is_heap(asm, object_opnd, side_exit)
|
def guard_object_is_heap(jit, ctx, asm, object, object_opnd, counter = nil)
|
||||||
|
object_type = ctx.get_opnd_type(object_opnd)
|
||||||
|
if object_type.heap?
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
side_exit = side_exit(jit, ctx)
|
||||||
|
side_exit = counted_exit(side_exit, counter) if counter
|
||||||
|
|
||||||
asm.comment('guard object is heap')
|
asm.comment('guard object is heap')
|
||||||
# Test that the object is not an immediate
|
# Test that the object is not an immediate
|
||||||
asm.test(object_opnd, C::RUBY_IMMEDIATE_MASK)
|
asm.test(object, C::RUBY_IMMEDIATE_MASK)
|
||||||
asm.jnz(side_exit)
|
asm.jnz(side_exit)
|
||||||
|
|
||||||
# Test that the object is not false
|
# Test that the object is not false
|
||||||
asm.cmp(object_opnd, Qfalse)
|
asm.cmp(object, Qfalse)
|
||||||
asm.je(side_exit)
|
asm.je(side_exit)
|
||||||
|
|
||||||
|
if object_type.diff(Type::UnknownHeap) != TypeDiff::Incompatible
|
||||||
|
ctx.upgrade_opnd_type(object_opnd, Type::UnknownHeap)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param asm [RubyVM::RJIT::Assembler]
|
# @param asm [RubyVM::RJIT::Assembler]
|
||||||
@ -3859,7 +3874,7 @@ module RubyVM::RJIT
|
|||||||
# @param jit [RubyVM::RJIT::JITState]
|
# @param jit [RubyVM::RJIT::JITState]
|
||||||
# @param ctx [RubyVM::RJIT::Context]
|
# @param ctx [RubyVM::RJIT::Context]
|
||||||
# @param asm [RubyVM::RJIT::Assembler]
|
# @param asm [RubyVM::RJIT::Assembler]
|
||||||
def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id, obj_opnd = nil)
|
def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id, obj_opnd, obj_yarv_opnd)
|
||||||
side_exit = side_exit(jit, ctx)
|
side_exit = side_exit(jit, ctx)
|
||||||
starting_ctx = ctx.dup # copy for jit_chain_guard
|
starting_ctx = ctx.dup # copy for jit_chain_guard
|
||||||
|
|
||||||
@ -3898,7 +3913,7 @@ module RubyVM::RJIT
|
|||||||
end
|
end
|
||||||
|
|
||||||
asm.mov(:rax, obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
|
asm.mov(:rax, obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
|
||||||
guard_object_is_heap(asm, :rax, counted_exit(side_exit, :getivar_not_heap))
|
guard_object_is_heap(jit, ctx, asm, :rax, obj_yarv_opnd, :getivar_not_heap)
|
||||||
|
|
||||||
shape_id = C.rb_shape_get_shape_id(comptime_obj)
|
shape_id = C.rb_shape_get_shape_id(comptime_obj)
|
||||||
if shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
|
if shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
|
||||||
@ -5035,7 +5050,7 @@ module RubyVM::RJIT
|
|||||||
return CantCompile
|
return CantCompile
|
||||||
end
|
end
|
||||||
|
|
||||||
jit_getivar(jit, ctx, asm, comptime_recv, ivar_id, recv_opnd)
|
jit_getivar(jit, ctx, asm, comptime_recv, ivar_id, recv_opnd, StackOpnd[0])
|
||||||
end
|
end
|
||||||
|
|
||||||
# vm_call_bmethod
|
# vm_call_bmethod
|
||||||
@ -5508,10 +5523,11 @@ module RubyVM::RJIT
|
|||||||
asm.comment('push_splat_args')
|
asm.comment('push_splat_args')
|
||||||
|
|
||||||
array_opnd = ctx.stack_opnd(0)
|
array_opnd = ctx.stack_opnd(0)
|
||||||
|
array_stack_opnd = StackOpnd[0]
|
||||||
array_reg = :rax
|
array_reg = :rax
|
||||||
asm.mov(array_reg, array_opnd)
|
asm.mov(array_reg, array_opnd)
|
||||||
|
|
||||||
guard_object_is_heap(asm, array_reg, counted_exit(side_exit, :send_args_splat_not_array))
|
guard_object_is_heap(jit, ctx, asm, array_reg, array_stack_opnd, :send_args_splat_not_array)
|
||||||
guard_object_is_array(asm, array_reg, :rcx, counted_exit(side_exit, :send_args_splat_not_array))
|
guard_object_is_array(asm, array_reg, :rcx, counted_exit(side_exit, :send_args_splat_not_array))
|
||||||
|
|
||||||
array_len_opnd = :rcx
|
array_len_opnd = :rcx
|
||||||
|
@ -1,25 +1,78 @@
|
|||||||
module RubyVM::RJIT
|
module RubyVM::RJIT
|
||||||
# Represent the type of a value (local/stack/self) in RJIT
|
# Represent the type of a value (local/stack/self) in RJIT
|
||||||
Type = Data.define(:type) do
|
Type = Data.define(:type) do
|
||||||
|
# Check if the type is an immediate
|
||||||
|
def imm?
|
||||||
|
case self
|
||||||
|
in Type::UnknownImm then true
|
||||||
|
in Type::Nil then true
|
||||||
|
in Type::True then true
|
||||||
|
in Type::False then true
|
||||||
|
in Type::Fixnum then true
|
||||||
|
in Type::Flonum then true
|
||||||
|
in Type::ImmSymbol then true
|
||||||
|
else false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if the type is a heap object
|
||||||
|
def heap?
|
||||||
|
case self
|
||||||
|
in Type::UnknownHeap then true
|
||||||
|
in Type::TArray then true
|
||||||
|
in Type::CArray then true
|
||||||
|
in Type::Hash then true
|
||||||
|
in Type::HeapSymbol then true
|
||||||
|
in Type::TString then true
|
||||||
|
in Type::CString then true
|
||||||
|
in Type::BlockParamProxy then true
|
||||||
|
else false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Returns a boolean representing whether the value is truthy if known, otherwise nil
|
# Returns a boolean representing whether the value is truthy if known, otherwise nil
|
||||||
def known_truthy
|
def known_truthy
|
||||||
case self
|
case self
|
||||||
in Type::Nil | Type::False
|
in Type::Nil then false
|
||||||
false
|
in Type::False then false
|
||||||
in Type::UnknownHeap
|
in Type::UnknownHeap then false
|
||||||
true
|
in Type::Unknown | Type::UnknownImm then nil
|
||||||
in Type::Unknown | Type::UnknownImm
|
else true
|
||||||
nil
|
|
||||||
else
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def diff(dst)
|
def diff(dst)
|
||||||
|
# Perfect match, difference is zero
|
||||||
if self == dst
|
if self == dst
|
||||||
return TypeDiff::Compatible[0]
|
return TypeDiff::Compatible[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Any type can flow into an unknown type
|
||||||
|
if dst == Type::Unknown
|
||||||
|
return TypeDiff::Compatible[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
# A CString is also a TString.
|
||||||
|
if self == Type::CString && dst == Type::TString
|
||||||
|
return TypeDiff::Compatible[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
# A CArray is also a TArray.
|
||||||
|
if self == Type::CArray && dst == Type::TArray
|
||||||
|
return TypeDiff::Compatible[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Specific heap type into unknown heap type is imperfect but valid
|
||||||
|
if self.heap? && dst == Type::UnknownHeap
|
||||||
|
return TypeDiff::Compatible[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Specific immediate type into unknown immediate type is imperfect but valid
|
||||||
|
if self.imm? && dst == Type::UnknownImm
|
||||||
|
return TypeDiff::Compatible[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Incompatible types
|
||||||
return TypeDiff::Incompatible
|
return TypeDiff::Incompatible
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user