summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2020-07-10 11:49:50 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2020-07-13 08:56:18 +0900
commit9721f477c7f33d64af94fad4a1ca51f739b0b08f (patch)
tree14330998f33e9040a7038b80899098c016a26241
parentf66e0212efe4f6572d5e81741e831ab735cc2fee (diff)
inline Primitive.cexpr!
We can obtain the verbatim source code of Primitive.cexpr!. Why not paste that content into the JITed program.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3305
-rw-r--r--integer.rb4
-rw-r--r--internal/numeric.h4
-rw-r--r--internal/object.h1
-rw-r--r--numeric.c12
-rw-r--r--object.c2
-rw-r--r--tool/mk_builtin_loader.rb81
-rw-r--r--tool/ruby_vm/helpers/c_escape.rb2
7 files changed, 74 insertions, 32 deletions
diff --git a/integer.rb b/integer.rb
index daf11b088f..f2f1e79a5e 100644
--- a/integer.rb
+++ b/integer.rb
@@ -15,7 +15,7 @@ class Integer
# 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
# 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 219e739e7d..87f5559390 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -75,7 +75,6 @@ VALUE rb_int_divmod(VALUE x, VALUE y);
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);
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 a05abbf971..d34f498ee1 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -35,6 +35,7 @@ VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
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 b883b30440..b59c3198cc 100644
--- a/numeric.c
+++ b/numeric.c
@@ -794,6 +794,12 @@ int_zero_p(VALUE num)
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)
}
}
+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 a684927d10..b47635f1fd 100644
--- a/object.c
+++ b/object.c
@@ -591,7 +591,7 @@ rb_obj_itself(VALUE obj)
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 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