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

ruby-changes:58922

From: Koichi <ko1@a...>
Date: Wed, 27 Nov 2019 03:57:52 +0900 (JST)
Subject: [ruby-changes:58922] a3e6f52c17 (master): rename __builtin_inline!(code) and introduce others.

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

From a3e6f52c17061f012c4e638b3343b57752ed7603 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Tue, 26 Nov 2019 12:20:53 +0900
Subject: rename __builtin_inline!(code) and introduce others.

rename __builtin_inline!(code) to __builtin_cstmt(code).
Also this commit introduce the following inlining C code features.

* __builtin_cstmt!(STMT)

(renamed from __builtin_inline!)

Define a function which run STMT implicitly and call this function at
evatuation time. Note that you need to return some value in STMT.
If there is a local variables (includes method parameters), you can
read these values.

  static VALUE func(ec, self) {
    VALUE x = ...;
    STMT
  }

Usage:
  def double a
    # a is readable from C code.
    __builtin_cstmt! 'return INT2FIX(FIX2INT(a) * 2);'
  end

* __builtin_cexpr!(EXPR)

Define a function which invoke EXPR implicitly like `__builtin_cstmt!`.
Different from cstmt!, which compiled with `return EXPR;`.
(`return` and `;` are added implicitly)

  static VALUE func(ec, self) {
    VALUE x = ...;
    return EXPPR;
  }

Usage:
  def double a
    __builtin_cexpr! 'INT2FIX(FIX2INT(a) * 2)'
  end

* __builtin_cconst!(EXPR)

Define a function which invoke EXPR implicitly like cexpr!.
However, the function is called once at compile time, not evaluated time.
Any local variables are not accessible (because there is no local variable
at compile time).

Usage:
  GCC = __builtin_cconst! '__GNUC__'

* __builtin_cinit!(STMT)

STMT are writtein in auto-generated code.
This code does not return any value.

Usage:

  __builtin_cinit! '#include <zlib.h>'
  def no_compression?
    __builtin_cconst! 'Z_NO_COMPRESSION ? Qtrue : Qfalse'
  end

diff --git a/compile.c b/compile.c
index b73b985..1d5aa84 100644
--- a/compile.c
+++ b/compile.c
@@ -6920,17 +6920,30 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in https://github.com/ruby/ruby/blob/trunk/compile.c#L6920
         }
         else {
             char inline_func[0x20];
+            bool cconst = false;
           retry:;
             const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
 
             if (bf == NULL) {
-                if (strcmp("inline!", builtin_func) == 0) {
+                if (strcmp("cstmt!", builtin_func) == 0 ||
+                    strcmp("cexpr!", builtin_func) == 0) {
+                  inlinec:;
                     int inline_index = GET_VM()->builtin_inline_index++;
-                    snprintf(inline_func, 0x20, "rb_compiled_inline%d", inline_index);
+                    snprintf(inline_func, 0x20, "builtin_inline%d", inline_index);
                     builtin_func = inline_func;
                     args_node = NULL;
                     goto retry;
                 }
+                else if (strcmp("cconst!", builtin_func) == 0) {
+                    cconst = true;
+                    goto inlinec;
+                }
+                else if (strcmp("cinit!", builtin_func) == 0) {
+                    // ignore
+                    GET_VM()->builtin_inline_index++;
+                    return COMPILE_OK;
+                }
+
                 if (1) {
                     rb_bug("can't find builtin function:%s", builtin_func);
                 }
@@ -6940,6 +6953,13 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in https://github.com/ruby/ruby/blob/trunk/compile.c#L6953
                 return COMPILE_NG;
             }
 
+            if (cconst) {
+                typedef VALUE(*builtin_func0)(void *, VALUE);
+                VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
+                ADD_INSN1(ret, line, putobject, const_val);
+                return COMPILE_OK;
+            }
+
             // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
 
             argc = setup_args(iseq, args, args_node, &flag, &keywords);
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index 87eb042..5419c11 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -1,4 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L1
 
+def inline_text argc, prev_insn
+  raise "argc (#{argc}) of inline! should be 1" unless argc == 1
+  raise "1st argument should be string literal" unless prev_insn[0] == :putstring
+  prev_insn[1].rstrip
+end
+
 def collect_builtin base, iseq_ary, bs, inlines
   code = iseq_ary[13]
   params = iseq_ary[10]
@@ -24,14 +30,29 @@ def collect_builtin base, iseq_ary, bs, inlines https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L30
         func_name = $1
         argc = ci[:orig_argc]
 
-        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].rstrip
-
-          func_name = "rb_compiled_inline#{inlines.size}"
-          inlines << [func_name, [lineno, text, params]]
-          argc -= 1
+        if /(.+)\!\z/ =~ func_name
+          case $1
+          when 'cstmt'
+            text = inline_text argc, prev_insn
+
+            func_name = "builtin_inline#{inlines.size}"
+            inlines << [func_name, [lineno, text, params]]
+            argc -= 1
+
+          when 'cexpr', 'cconst'
+            text = inline_text argc, prev_insn
+            code = "return #{text};"
+
+            func_name = "builtin_inline#{inlines.size}"
+            params = [] if $1 == 'cconst'
+            inlines << [func_name, [lineno, code, params]]
+            argc -= 1
+          when 'cinit'
+            text = inline_text argc, prev_insn
+            func_name = nil
+            inlines << [nil, [lineno, text, nil]]
+            argc -= 1
+          end
         end
 
         if bs[func_name] &&
@@ -39,7 +60,7 @@ def collect_builtin base, iseq_ary, bs, inlines https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L60
           raise "same builtin function \"#{func_name}\", but different arity (was #{bs[func_name]} but #{argc})"
         end
 
-        bs[func_name] = argc
+        bs[func_name] = argc if func_name
       end
     else
       insn[1..-1].each{|op|
@@ -76,25 +97,36 @@ def mk_builtin_header file https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L97
     f.puts "//   with #{file}"
     f.puts
     lineno = 6
+    line_file = file.gsub('\\', '/')
 
     inlines.each{|name, (body_lineno, text, params)|
-      f.puts "static VALUE #{name}(rb_execution_context_t *ec, const VALUE self) {"
-      lineno += 1
+      if name
+        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});"
+        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} \"#{line_file}\""
         lineno += 1
-      }
-      f.puts "#line #{body_lineno} \"#{file}\""
-      lineno += 1
 
-      f.puts text
-      lineno += text.count("\n") + 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 "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number.
+        f.puts "}"
+        lineno += 2
+      else
+        # cinit!
+        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.
+        lineno += 1
+      end
     }
 
     f.puts "static void load_#{base}(void)"
-- 
cgit v0.10.2


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

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