aboutsummaryrefslogtreecommitdiffstats
path: root/tool
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2019-11-11 16:38:46 +0900
committerKoichi Sasada <ko1@atdot.net>2019-11-11 16:47:50 +0900
commit31416423809f64d4b5ea6b9651cced3179cc5ced (patch)
tree5cf4b7d9b19019d5f665ca0b0c3902f8100cd597 /tool
parent05a5c69e1a06a3853afb3744fa9925910b78904f (diff)
downloadruby-31416423809f64d4b5ea6b9651cced3179cc5ced.tar.gz
__builtin_inline!
Add an experimental `__builtin_inline!(c_expression)` special intrinsic which run a C code snippet. In `c_expression`, you can access the following variables: * ec (rb_execution_context_t *) * self (const VALUE) * local variables (const VALUE) Not that you can read these variables, but you can not write them. You need to return from this expression and return value will be a result of __builtin_inline!(). Examples: `def foo(x) __builtin_inline!('return rb_p(x);'); end` calls `p(x)`. `def double(x) __builtin_inline!('return INT2NUM(NUM2INT(x) * 2);')` returns x*2.
Diffstat (limited to 'tool')
-rw-r--r--tool/mk_builtin_loader.rb58
1 files changed, 53 insertions, 5 deletions
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index 4f140a6f6b..8f4d5df60b 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -1,8 +1,21 @@
-def collect_builtin iseq_ary, bs
+def collect_builtin base, iseq_ary, bs, inlines
code = iseq_ary[13]
+ params = iseq_ary[10]
+ prev_insn = nil
+ lineno = nil
code.each{|insn|
+ case insn
+ when Array
+ # ok
+ when Integer
+ lineno = insn
+ next
+ else
+ next
+ end
+
next unless Array === insn
case insn[0]
when :send
@@ -11,18 +24,31 @@ def collect_builtin iseq_ary, bs
func_name = $1
argc = ci[:orig_argc]
- if bs[func_name] && bs[func_name] != argc
- raise
+ if func_name == 'inline!'
+ raise "argc (#{argc}) of inline! should be 1" unless argc == 1
+ raise "1st argument should be string literal" unless prev_insn[0] == :putstring
+ text = prev_insn[1]
+
+ func_name = "__builtin_inline#{inlines.size}"
+ inlines << [func_name, [lineno, text, params]]
+ argc -= 1
end
+
+ if bs[func_name] &&
+ bs[func_name] != argc
+ raise "same builtin function \"#{func_name}\", but different arity (was #{bs[func_name]} but #{argc})"
+ end
+
bs[func_name] = argc
end
else
insn[1..-1].each{|op|
if op.is_a?(Array) && op[0] == "YARVInstructionSequence/SimpleDataFormat"
- collect_builtin op, bs
+ collect_builtin base, op, bs, inlines
end
}
end
+ prev_insn = insn
}
end
# ruby mk_builtin_loader.rb TARGET_FILE.rb
@@ -33,7 +59,8 @@ def mk_builtin_header file
base = File.basename(file, '.rb')
ofile = "#{base}.rbinc"
- collect_builtin(RubyVM::InstructionSequence.compile_file(file, false).to_a, bs = {})
+ # bs = { func_name => argc }
+ collect_builtin(base, RubyVM::InstructionSequence.compile_file(file, false).to_a, bs = {}, inlines = [])
open(ofile, 'w'){|f|
f.puts "// -*- c -*-"
@@ -42,6 +69,27 @@ def mk_builtin_header file
f.puts "// by #{__FILE__}"
f.puts "// with #{file}"
f.puts
+ lineno = 6
+
+ inlines.each{|name, (body_lineno, text, params)|
+ f.puts "static VALUE #{name}(rb_execution_context_t *ec, const VALUE self) {"
+ lineno += 1
+
+ params.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
+ }
+ f.puts "#line #{body_lineno} \"#{file}\""
+ lineno += 1
+
+ f.puts text
+ lineno += text.count("\n") + 1
+
+ f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number.
+ f.puts "}"
+ lineno += 2
+ }
f.puts "static void load_#{base}(void)"
f.puts "{"