[前][次][番号順一覧][スレッド一覧]

ruby-changes:62201

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Mon, 13 Jul 2020 08:56:47 +0900 (JST)
Subject: [ruby-changes:62201] 9721f477c7 (master): inline Primitive.cexpr!

https://git.ruby-lang.org/ruby.git/commit/?id=9721f477c7

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?=
 <shyouhei@r...>
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.

diff --git a/integer.rb b/integer.rb
index daf11b0..f2f1e79 100644
--- a/integer.rb
+++ b/integer.rb
@@ -15,7 +15,7 @@ class Integer https://github.com/ruby/ruby/blob/trunk/integer.rb#L15
   #  Returns +true+ if +int+ is an even number.
   def even?
     Primitive.attr! 'inline'
-    Primitive.cexpr! 'int_even_p(self)'
+    Primitive.cexpr! 'rb_int_even_p(self)'
   end
 
   #  call-seq:
@@ -79,6 +79,6 @@ class Integer https://github.com/ruby/ruby/blob/trunk/integer.rb#L79
   # Returns +true+ if +int+ has a zero value.
   def zero?
     Primitive.attr! 'inline'
-    Primitive.cexpr! 'int_zero_p(self)'
+    Primitive.cexpr! 'rb_int_zero_p(self)'
   end
 end
diff --git a/internal/numeric.h b/internal/numeric.h
index 219e739..87f5559 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -75,7 +75,6 @@ VALUE rb_int_divmod(VALUE x, VALUE y); https://github.com/ruby/ruby/blob/trunk/internal/numeric.h#L75
 VALUE rb_int_and(VALUE x, VALUE y);
 VALUE rb_int_lshift(VALUE x, VALUE y);
 VALUE rb_int_div(VALUE x, VALUE y);
-VALUE rb_int_abs(VALUE num);
 VALUE rb_int_odd_p(VALUE num);
 int rb_int_positive_p(VALUE num);
 int rb_int_negative_p(VALUE num);
@@ -107,6 +106,9 @@ VALUE rb_float_equal(VALUE x, VALUE y); https://github.com/ruby/ruby/blob/trunk/internal/numeric.h#L106
 int rb_float_cmp(VALUE x, VALUE y);
 VALUE rb_float_eql(VALUE x, VALUE y);
 VALUE rb_fix_aref(VALUE fix, VALUE idx);
+VALUE rb_int_zero_p(VALUE num);
+VALUE rb_int_even_p(VALUE num);
+VALUE rb_int_abs(VALUE num);
 MJIT_SYMBOL_EXPORT_END
 
 static inline bool
diff --git a/internal/object.h b/internal/object.h
index a05abbf..d34f498 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -35,6 +35,7 @@ VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); https://github.com/ruby/ruby/blob/trunk/internal/object.h#L35
 void rb_obj_copy_ivar(VALUE dest, VALUE obj);
 VALUE rb_false(VALUE obj);
 VALUE rb_convert_type_with_id(VALUE v, int t, const char* nam, ID mid);
+VALUE rb_obj_size(VALUE self, VALUE args, VALUE obj);
 MJIT_SYMBOL_EXPORT_END
 
 static inline void
diff --git a/numeric.c b/numeric.c
index b883b30..b59c319 100644
--- a/numeric.c
+++ b/numeric.c
@@ -794,6 +794,12 @@ int_zero_p(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L794
     return Qfalse;
 }
 
+VALUE
+rb_int_zero_p(VALUE num)
+{
+    return int_zero_p(num);
+}
+
 /*
  *  call-seq:
  *     num.nonzero?  ->  self or nil
@@ -3250,6 +3256,12 @@ int_even_p(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3256
     }
 }
 
+VALUE
+rb_int_even_p(VALUE num)
+{
+    return int_even_p(num);
+}
+
 /*
  *  call-seq:
  *     int.allbits?(mask)  ->  true or false
diff --git a/object.c b/object.c
index a684927..b47635f 100644
--- a/object.c
+++ b/object.c
@@ -591,7 +591,7 @@ rb_obj_itself(VALUE obj) https://github.com/ruby/ruby/blob/trunk/object.c#L591
     return obj;
 }
 
-static VALUE
+VALUE
 rb_obj_size(VALUE self, VALUE args, VALUE obj)
 {
     return LONG2FIX(1);
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index 4efdde3..8f78b66 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -1,6 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L1
 # 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 https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L209
   }
 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 https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L269
 
     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 https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L288
       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 3e2bf2e..fa3cb8b 100644
--- a/tool/ruby_vm/helpers/c_escape.rb
+++ b/tool/ruby_vm/helpers/c_escape.rb
@@ -46,7 +46,7 @@ module RubyVM::CEscape https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/helpers/c_escape.rb#L46
     # 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 v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]