summaryrefslogtreecommitdiff
path: root/tool
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-07-04 17:23:34 +0900
committerKoichi Sasada <ko1@atdot.net>2020-07-04 17:28:23 +0900
commit74e1bca79d703f2658ac9cfa6d990e7e77c59757 (patch)
tree5a204eb1bf1765239b4accd0f91e736ce7b272bf /tool
parent7a5da7d55d40e431e561ab2c891b7cab155e74db (diff)
support all locals for cexpr!, cstmt!
Primitve.cexpr! and .cstmt! can access Ruby's parameter and *local variables* (note that local parameters are also local variables). However recent changes only allow to access parameters. This patch fix it. For example, the following code can work: def foo a, b, k: :kw, **kwrest c = a + b d = k e = kwrest p Primitive.cstmt!(%q(rb_p(rb_ary_new_from_args(5, a, b, c, d, e)); return Qnil;)) end
Diffstat (limited to 'tool')
-rw-r--r--tool/mk_builtin_loader.rb77
1 files changed, 50 insertions, 27 deletions
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index 1aa52c671c..cec0556f7a 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -49,37 +49,28 @@ def make_cfunc_name inlines, name, lineno
end
end
-def collect_params tree
- while tree
- case tree.first
- when :params
- params = []
- _, mand, opt, rest, post, kwds, kwrest, block = tree
- mand.each {|_, v| params << v.to_sym} if mand
- opt.each {|(_, v), | params << v.to_sym} if opt
- params << rest[1][1].to_sym if rest
- post.each {|_, v| params << v.to_sym} if post
- params << kwrest[1][1].to_sym if kwrest
- params << block[1][1].to_sym if block
- return params
- when :paren
- tree = tree[1]
- else
- raise "unknown sexp: #{tree.first}"
+def collect_locals tree
+ type, name, (line, cols) = tree
+ if locals = LOCALS_DB[[name, line]]
+ locals
+ else
+ if false # for debugging
+ pp LOCALS_DB
+ raise "not found: [#{name}, #{line}]"
end
end
end
-def collect_builtin base, tree, name, bs, inlines, params = nil
+def collect_builtin base, tree, name, bs, inlines, locals = nil
while tree
call = recv = sep = mid = args = nil
case tree.first
when :def
- params = collect_params(tree[2])
+ locals = collect_locals(tree[1])
tree = tree[3]
next
when :defs
- params = collect_params(tree[4])
+ locals = collect_locals(tree[3])
tree = tree[5]
next
when :class
@@ -146,7 +137,7 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
func_name = "_bi#{inlines.size}"
cfunc_name = make_cfunc_name(inlines, name, lineno)
- inlines[cfunc_name] = [lineno, text, params, func_name]
+ inlines[cfunc_name] = [lineno, text, locals, func_name]
argc -= 1
when 'cexpr', 'cconst'
text = inline_text argc, args.first
@@ -155,8 +146,8 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
func_name = "_bi#{inlines.size}"
cfunc_name = make_cfunc_name(inlines, name, lineno)
- params = [] if $1 == 'cconst'
- inlines[cfunc_name] = [lineno, code, params, func_name]
+ locals = [] if $1 == 'cconst'
+ inlines[cfunc_name] = [lineno, code, locals, func_name]
argc -= 1
when 'cinit'
text = inline_text argc, args.first
@@ -177,21 +168,53 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
end
tree.each do |t|
- collect_builtin base, t, name, bs, inlines, params if Array === t
+ collect_builtin base, t, name, bs, inlines, locals if Array === t
end
break
end
end
+
# ruby mk_builtin_loader.rb TARGET_FILE.rb
# #=> generate TARGET_FILE.rbinc
#
+LOCALS_DB = {} # [method_name, first_line] = locals
+
+def collect_iseq iseq_ary
+ # iseq_ary.each_with_index{|e, i| p [i, e]}
+ label = iseq_ary[5]
+ first_line = iseq_ary[8]
+ type = iseq_ary[9]
+ locals = iseq_ary[10]
+ insns = iseq_ary[13]
+
+ if type == :method
+ LOCALS_DB[[label, first_line].freeze] = locals
+ end
+
+ insns.each{|insn|
+ case insn
+ when Integer
+ # ignore
+ when Array
+ # p insn.shift # insn name
+ insn.each{|op|
+ if Array === op && op[0] == "YARVInstructionSequence/SimpleDataFormat"
+ collect_iseq op
+ end
+ }
+ end
+ }
+end
+
def mk_builtin_header file
base = File.basename(file, '.rb')
ofile = "#{file}inc"
# bs = { func_name => argc }
- collect_builtin(base, Ripper.sexp(File.read(file)), 'top', bs = {}, inlines = {})
+ code = File.read(file)
+ collect_iseq RubyVM::InstructionSequence.compile(code).to_a
+ collect_builtin(base, Ripper.sexp(code), 'top', bs = {}, inlines = {})
begin
f = open(ofile, 'w')
@@ -219,12 +242,12 @@ def mk_builtin_header file
lineno = __LINE__ - lineno - 1
line_file = file
- inlines.each{|cfunc_name, (body_lineno, text, params, func_name)|
+ inlines.each{|cfunc_name, (body_lineno, text, locals, func_name)|
if String === cfunc_name
f.puts "static VALUE #{cfunc_name}(struct rb_execution_context_struct *ec, const VALUE self) {"
lineno += 1
- params.reverse_each.with_index{|param, i|
+ locals.reverse_each.with_index{|param, i|
next unless Symbol === param
f.puts "MAYBE_UNUSED(const VALUE) #{param} = rb_vm_lvar(ec, #{-3 - i});"
lineno += 1