From 9721f477c7f33d64af94fad4a1ca51f739b0b08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Fri, 10 Jul 2020 11:49:50 +0900 Subject: inline Primitive.cexpr! We can obtain the verbatim source code of Primitive.cexpr!. Why not paste that content into the JITed program. --- tool/mk_builtin_loader.rb | 81 ++++++++++++++++++++++++++-------------- tool/ruby_vm/helpers/c_escape.rb | 2 +- 2 files changed, 55 insertions(+), 28 deletions(-) (limited to 'tool') diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb index 4efdde3023..8f78b660d8 100644 --- a/tool/mk_builtin_loader.rb +++ b/tool/mk_builtin_loader.rb @@ -1,6 +1,8 @@ # Parse built-in script and make rbinc file require 'ripper' +require 'stringio' +require_relative 'ruby_vm/helpers/c_escape' def string_literal(lit, str = []) while lit @@ -207,6 +209,29 @@ def collect_iseq iseq_ary } end +def generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_name) + f = StringIO.new + f.puts '{' + lineno += 1 + 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 + } + f.puts "#line #{body_lineno} \"#{line_file}\"" + lineno += 1 + + f.puts text + lineno += text.count("\n") + 1 + + f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number. + f.puts "}" + f.puts + lineno += 3 + + return lineno, f.string +end + def mk_builtin_header file base = File.basename(file, '.rb') ofile = "#{file}inc" @@ -244,23 +269,10 @@ def mk_builtin_header file 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 - - 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 - } - f.puts "#line #{body_lineno} \"#{line_file}\"" + f.puts "static VALUE #{cfunc_name}(struct rb_execution_context_struct *ec, const VALUE self)" lineno += 1 - - f.puts text - lineno += text.count("\n") + 1 - - f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number. - f.puts "}" - lineno += 2 + lineno, str = generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_name) + f.write str else # cinit! f.puts "#line #{body_lineno} \"#{line_file}\"" @@ -276,17 +288,32 @@ def mk_builtin_header file f.puts %'static void' f.puts %'mjit_compile_invokebuiltin_for_#{func}(FILE *f, long index)' f.puts %'{' - f.puts %' if (index > 0) {' - f.puts %' fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\\n");' - f.puts %' fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\\n", index);' - f.puts %' }' - f.puts %' else if (index == 0) {' - f.puts %' fprintf(f, " const VALUE *argv = NULL;\\n");' - f.puts %' }' - f.puts %' else {' - f.puts %' fprintf(f, " const VALUE *argv = STACK_ADDR_FROM_TOP(%d);\\n", #{argc});' - f.puts %' }' - f.puts %' fprintf(f, " val = builtin_invoker#{argc}(ec, GET_SELF(), argv, %p);\\n", (const void *)#{cfunc_name});' + if inlines.has_key? cfunc_name + f.puts %' fprintf(f, " MAYBE_UNUSED(VALUE) self = GET_SELF();\\n");' + body_lineno, text, locals, func_name = inlines[cfunc_name] + lineno, str = generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_name) + str.each_line {|i| + f.printf(%' fprintf(f, "%%s", %s);\n', RubyVM::CEscape.rstring2cstr(i.sub(/^return\b/ , ' val ='))) + } + else + decl = ', VALUE' * argc + argv = argc \ + . times \ + . map {|i|", argv[#{i}]"} \ + . join('') + f.puts %' fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE#{decl});\\n");' + if argc > 0 + f.puts %' if (index == -1) {' + f.puts %' fprintf(f, " const VALUE *argv = STACK_ADDR_FROM_TOP(%d);\\n", #{argc});' + f.puts %' }' + f.puts %' else {' + f.puts %' fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\\n");' + f.puts %' fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\\n", index);' + f.puts %' }' + end + f.puts %' fprintf(f, " func f = (func)%p\\n;", (const void *)#{cfunc_name});' + f.puts %' fprintf(f, " val = f(ec, GET_SELF()#{argv});\\n");' + end f.puts %'}' f.puts } diff --git a/tool/ruby_vm/helpers/c_escape.rb b/tool/ruby_vm/helpers/c_escape.rb index 3e2bf2e02c..fa3cb8b1aa 100644 --- a/tool/ruby_vm/helpers/c_escape.rb +++ b/tool/ruby_vm/helpers/c_escape.rb @@ -46,7 +46,7 @@ module RubyVM::CEscape # I believe this is the fastest implementation done in pure-ruby. # Constants cached, gsub skips block evaluation, string literal optimized. buf = str.b - buf.gsub! %r/./n, RString2CStr + buf.gsub! %r/./nm, RString2CStr return %'"#{buf}"' end -- cgit v1.2.3