Skip to content

Commit

Permalink
RJIT: Implement checkkeyword
Browse files Browse the repository at this point in the history
  • Loading branch information
k0kubun committed Mar 19, 2023
1 parent 67dd52d commit 9f8e914
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 10 deletions.
42 changes: 39 additions & 3 deletions lib/ruby_vm/rjit/insn_compiler.rb
Expand Up @@ -18,7 +18,7 @@ def compile(jit, ctx, asm, insn)
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)
Expand Down Expand Up @@ -66,7 +66,7 @@ def compile(jit, ctx, asm, insn)
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
Expand Down Expand Up @@ -1154,7 +1154,43 @@ def definedivar(jit, ctx, asm)
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
Expand Down
16 changes: 12 additions & 4 deletions rjit_c.rb
Expand Up @@ -1001,6 +1001,18 @@ def C.rb_iseq_location_t
)
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)"),
Expand Down Expand Up @@ -1354,10 +1366,6 @@ def C.rb_iseq_type
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
Expand Down
19 changes: 16 additions & 3 deletions tool/rjit/bindgen.rb
Expand Up @@ -156,8 +156,8 @@ def generate(nodes)
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
Expand All @@ -169,7 +169,7 @@ def generate(nodes)
# 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
Expand Down Expand Up @@ -201,6 +201,18 @@ def generate(nodes)

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
Expand Down Expand Up @@ -573,6 +585,7 @@ def push_target(target)
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
Expand Down

0 comments on commit 9f8e914

Please sign in to comment.