RJIT: Find a best matching block version
This commit is contained in:
parent
eb51248c4c
commit
3bacc3877a
@ -354,8 +354,25 @@ module RubyVM::RJIT
|
|||||||
# @param [RubyVM::RJIT::Context] ctx
|
# @param [RubyVM::RJIT::Context] ctx
|
||||||
# @return [RubyVM::RJIT::Block,NilClass]
|
# @return [RubyVM::RJIT::Block,NilClass]
|
||||||
def find_block(iseq, pc, ctx)
|
def find_block(iseq, pc, ctx)
|
||||||
src = ctx
|
versions = rjit_blocks(iseq)[pc]
|
||||||
rjit_blocks(iseq)[pc].find do |block|
|
|
||||||
|
best_version = nil
|
||||||
|
best_diff = Float::INFINITY
|
||||||
|
|
||||||
|
versions.each do |block|
|
||||||
|
# Note that we always prefer the first matching
|
||||||
|
# version found because of inline-cache chains
|
||||||
|
case ctx.diff(block.ctx)
|
||||||
|
in TypeDiff::Compatible[diff] if diff < best_diff
|
||||||
|
best_version = block
|
||||||
|
best_diff = diff
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return best_version
|
||||||
|
|
||||||
|
versions.find do |block|
|
||||||
dst = block.ctx
|
dst = block.ctx
|
||||||
|
|
||||||
# Can only lookup the first version in the chain
|
# Can only lookup the first version in the chain
|
||||||
|
@ -289,6 +289,74 @@ module RubyVM::RJIT
|
|||||||
self.local_types = [Type::Unknown] * MAX_LOCAL_TYPES
|
self.local_types = [Type::Unknown] * MAX_LOCAL_TYPES
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Compute a difference score for two context objects
|
||||||
|
def diff(dst)
|
||||||
|
# Self is the source context (at the end of the predecessor)
|
||||||
|
src = self
|
||||||
|
|
||||||
|
# Can only lookup the first version in the chain
|
||||||
|
if dst.chain_depth != 0
|
||||||
|
return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
|
||||||
|
# Blocks with depth > 0 always produce new versions
|
||||||
|
# Sidechains cannot overlap
|
||||||
|
if src.chain_depth != 0
|
||||||
|
return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
|
||||||
|
if dst.stack_size != src.stack_size
|
||||||
|
return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
|
||||||
|
if dst.sp_offset != src.sp_offset
|
||||||
|
return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
|
||||||
|
# Difference sum
|
||||||
|
diff = 0
|
||||||
|
|
||||||
|
# Check the type of self
|
||||||
|
diff += case src.self_type.diff(dst.self_type)
|
||||||
|
in TypeDiff::Compatible[diff] then diff
|
||||||
|
in TypeDiff::Incompatible then return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
|
||||||
|
# For each local type we track
|
||||||
|
src.local_types.size.times do |i|
|
||||||
|
t_src = src.local_types[i]
|
||||||
|
t_dst = dst.local_types[i]
|
||||||
|
diff += case t_src.diff(t_dst)
|
||||||
|
in TypeDiff::Compatible[diff] then diff
|
||||||
|
in TypeDiff::Incompatible then return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# For each value on the temp stack
|
||||||
|
src.stack_size.times do |i|
|
||||||
|
src_mapping, src_type = src.get_opnd_mapping(StackOpnd[i])
|
||||||
|
dst_mapping, dst_type = dst.get_opnd_mapping(StackOpnd[i])
|
||||||
|
|
||||||
|
# If the two mappings aren't the same
|
||||||
|
if src_mapping != dst_mapping
|
||||||
|
if dst_mapping == MapToStack
|
||||||
|
# We can safely drop information about the source of the temp
|
||||||
|
# stack operand.
|
||||||
|
diff += 1
|
||||||
|
else
|
||||||
|
return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
diff += case src_type.diff(dst_type)
|
||||||
|
in TypeDiff::Compatible[diff] then diff
|
||||||
|
in TypeDiff::Incompatible then return TypeDiff::Incompatible
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return TypeDiff::Compatible[diff]
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def assert(cond)
|
def assert(cond)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user