RJIT: Implement checkkeyword
This commit is contained in:
parent
67dd52d59c
commit
9f8e914943
@ -18,7 +18,7 @@ module RubyVM::RJIT
|
||||
asm.incr_counter(:rjit_insns_count)
|
||||
asm.comment("Insn: #{insn.name}")
|
||||
|
||||
# 77/102
|
||||
# 78/102
|
||||
case insn.name
|
||||
when :nop then nop(jit, ctx, asm)
|
||||
when :getlocal then getlocal(jit, ctx, asm)
|
||||
@ -66,7 +66,7 @@ module RubyVM::RJIT
|
||||
when :defined then defined(jit, ctx, asm)
|
||||
when :definedivar then definedivar(jit, ctx, asm)
|
||||
# checkmatch
|
||||
# checkkeyword
|
||||
when :checkkeyword then checkkeyword(jit, ctx, asm)
|
||||
# checktype
|
||||
# defineclass
|
||||
# definemethod
|
||||
@ -1154,7 +1154,43 @@ module RubyVM::RJIT
|
||||
end
|
||||
|
||||
# checkmatch
|
||||
# checkkeyword
|
||||
|
||||
def checkkeyword(jit, ctx, asm)
|
||||
# When a keyword is unspecified past index 32, a hash will be used
|
||||
# instead. This can only happen in iseqs taking more than 32 keywords.
|
||||
if jit.iseq.body.param.keyword.num >= 32
|
||||
return CantCompile
|
||||
end
|
||||
|
||||
# The EP offset to the undefined bits local
|
||||
bits_offset = jit.operand(0)
|
||||
|
||||
# The index of the keyword we want to check
|
||||
index = jit.operand(1, signed: true)
|
||||
|
||||
# Load environment pointer EP
|
||||
ep_reg = :rax
|
||||
jit_get_ep(asm, 0, reg: ep_reg)
|
||||
|
||||
# VALUE kw_bits = *(ep - bits)
|
||||
bits_opnd = [ep_reg, C.VALUE.size * -bits_offset]
|
||||
|
||||
# unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
|
||||
# if ((b & (0x01 << idx))) {
|
||||
#
|
||||
# We can skip the FIX2ULONG conversion by shifting the bit we test
|
||||
bit_test = 0x01 << (index + 1)
|
||||
asm.test(bits_opnd, bit_test)
|
||||
asm.mov(:rax, Qfalse)
|
||||
asm.mov(:rcx, Qtrue)
|
||||
asm.cmovz(:rax, :rcx)
|
||||
|
||||
stack_ret = ctx.stack_push
|
||||
asm.mov(stack_ret, :rax)
|
||||
|
||||
KeepCompiling
|
||||
end
|
||||
|
||||
# checktype
|
||||
# defineclass
|
||||
# definemethod
|
||||
|
16
rjit_c.rb
16
rjit_c.rb
@ -1001,6 +1001,18 @@ module RubyVM::RJIT # :nodoc: all
|
||||
)
|
||||
end
|
||||
|
||||
def C.rb_iseq_param_keyword
|
||||
@rb_iseq_param_keyword ||= CType::Struct.new(
|
||||
"rb_iseq_param_keyword", Primitive.cexpr!("SIZEOF(struct rb_iseq_param_keyword)"),
|
||||
num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), num)")],
|
||||
required_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), required_num)")],
|
||||
bits_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), bits_start)")],
|
||||
rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), rest_start)")],
|
||||
table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), table)")],
|
||||
default_values: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), default_values)")],
|
||||
)
|
||||
end
|
||||
|
||||
def C.rb_iseq_struct
|
||||
@rb_iseq_struct ||= CType::Struct.new(
|
||||
"rb_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_struct)"),
|
||||
@ -1354,10 +1366,6 @@ module RubyVM::RJIT # :nodoc: all
|
||||
CType::Stub.new(:rb_iseq_type)
|
||||
end
|
||||
|
||||
def C.rb_iseq_param_keyword
|
||||
CType::Stub.new(:rb_iseq_param_keyword)
|
||||
end
|
||||
|
||||
def C.iseq_insn_info
|
||||
CType::Stub.new(:iseq_insn_info)
|
||||
end
|
||||
|
@ -156,8 +156,8 @@ class BindingGenerator
|
||||
println
|
||||
end
|
||||
|
||||
# TODO: Support nested declarations
|
||||
nodes_index = nodes.group_by(&:spelling).transform_values do |values|
|
||||
# Build a hash table for type lookup by name
|
||||
nodes_index = flatten_nodes(nodes).group_by(&:spelling).transform_values do |values|
|
||||
# Try to search a declaration with definitions
|
||||
node_with_children = values.find { |v| !v.children.empty? }
|
||||
next node_with_children if node_with_children
|
||||
@ -169,7 +169,7 @@ class BindingGenerator
|
||||
# Define types
|
||||
@types.each do |type|
|
||||
unless definition = generate_node(nodes_index[type])
|
||||
raise "Failed to generate type: #{type}"
|
||||
raise "Failed to find or generate type: #{type}"
|
||||
end
|
||||
println " def C.#{type}"
|
||||
println "@#{type} ||= #{definition}".gsub(/^/, " ").chomp
|
||||
@ -201,6 +201,18 @@ class BindingGenerator
|
||||
|
||||
private
|
||||
|
||||
# Make an array that includes all top-level and nested nodes
|
||||
def flatten_nodes(nodes)
|
||||
result = []
|
||||
nodes.each do |node|
|
||||
unless node.children.empty?
|
||||
result.concat(flatten_nodes(node.children))
|
||||
end
|
||||
end
|
||||
result.concat(nodes) # prioritize top-level nodes
|
||||
result
|
||||
end
|
||||
|
||||
# Return code before BINDGEN_BEG and code after BINDGEN_END
|
||||
def split_ambles(src_path)
|
||||
lines = File.read(src_path).lines
|
||||
@ -573,6 +585,7 @@ generator = BindingGenerator.new(
|
||||
rb_shape_t
|
||||
rb_thread_struct
|
||||
rb_jit_func_t
|
||||
rb_iseq_param_keyword
|
||||
rjit_options
|
||||
],
|
||||
# #ifdef-dependent immediate types, which need Primitive.cexpr! for type detection
|
||||
|
Loading…
x
Reference in New Issue
Block a user