mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
precalc invokebuiltin destinations
Noticed that struct rb_builtin_function is a purely compile-time constant. MJIT can eliminate some runtime calculations by statically generate dedicated C code generator for each builtin functions.
This commit is contained in:
parent
5d02c1dd14
commit
f66e0212ef
Notes:
git
2020-07-13 08:56:53 +09:00
7 changed files with 77 additions and 15 deletions
24
builtin.h
24
builtin.h
|
@ -11,13 +11,17 @@ struct rb_builtin_function {
|
|||
// for load
|
||||
const int index;
|
||||
const char * const name;
|
||||
|
||||
// for jit
|
||||
void (*compiler)(FILE *, long);
|
||||
};
|
||||
|
||||
#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity) { \
|
||||
#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity, _compiler) {\
|
||||
.name = #_name, \
|
||||
.func_ptr = (void *)_fname, \
|
||||
.argc = _arity, \
|
||||
.index = _i \
|
||||
.index = _i, \
|
||||
.compiler = _compiler, \
|
||||
}
|
||||
|
||||
void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
|
||||
|
@ -76,4 +80,20 @@ struct builtin_binary {
|
|||
size_t bin_size;
|
||||
};
|
||||
|
||||
// mjit
|
||||
|
||||
RBIMPL_ATTR_MAYBE_UNUSED()
|
||||
static void
|
||||
mjit_invokebuiltin_default_compiler(FILE *f, const struct rb_builtin_function *bf, long index)
|
||||
{
|
||||
if (index >= 0) {
|
||||
fprintf(f, "val = vm_invoke_builtin(ec, GET_CFP(), %p, STACK_ADDR_FROM_TOP(%d));\n",
|
||||
(const void *)bf, bf->argc);
|
||||
}
|
||||
else {
|
||||
fprintf(f, "val = vm_invoke_builtin_delegate(ec, GET_CFP(), %p, %ld);\n",
|
||||
(const void *)bf, index);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BUILTIN_H_INCLUDED
|
||||
|
|
|
@ -1478,11 +1478,11 @@ DEFINE_INSN
|
|||
invokebuiltin
|
||||
(RB_BUILTIN bf)
|
||||
(...)
|
||||
(VALUE ret)
|
||||
(VALUE val)
|
||||
// attr bool leaf = false; /* anything can happen inside */
|
||||
// attr rb_snum_t sp_inc = 1 - bf->argc;
|
||||
{
|
||||
ret = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
|
||||
val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
|
||||
}
|
||||
|
||||
/* call specific function with args (same parameters) */
|
||||
|
@ -1490,10 +1490,10 @@ DEFINE_INSN
|
|||
opt_invokebuiltin_delegate
|
||||
(RB_BUILTIN bf, rb_num_t index)
|
||||
()
|
||||
(VALUE ret)
|
||||
(VALUE val)
|
||||
// attr bool leaf = false; /* anything can happen inside */
|
||||
{
|
||||
ret = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
|
||||
val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
|
||||
}
|
||||
|
||||
/* call specific function with args (same parameters) and leave */
|
||||
|
|
4
struct.c
4
struct.c
|
@ -316,9 +316,9 @@ opt_struct_aset(rb_execution_context_t *ec, VALUE self, VALUE val, VALUE idx)
|
|||
}
|
||||
|
||||
static const struct rb_builtin_function struct_aref_builtin =
|
||||
RB_BUILTIN_FUNCTION(0, struct_aref, opt_struct_aref, 1);
|
||||
RB_BUILTIN_FUNCTION(0, struct_aref, opt_struct_aref, 1, 0);
|
||||
static const struct rb_builtin_function struct_aset_builtin =
|
||||
RB_BUILTIN_FUNCTION(1, struct_aref, opt_struct_aset, 2);
|
||||
RB_BUILTIN_FUNCTION(1, struct_aref, opt_struct_aset, 2, 0);
|
||||
|
||||
static void
|
||||
define_aref_method(VALUE nstr, VALUE name, VALUE off)
|
||||
|
|
|
@ -272,6 +272,25 @@ def mk_builtin_header file
|
|||
end
|
||||
}
|
||||
|
||||
bs.each_pair{|func, (argc, cfunc_name)|
|
||||
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});'
|
||||
f.puts %'}'
|
||||
f.puts
|
||||
}
|
||||
|
||||
f.puts "void Init_builtin_#{base}(void)"
|
||||
f.puts "{"
|
||||
|
||||
|
@ -279,9 +298,9 @@ def mk_builtin_header file
|
|||
f.puts " // table definition"
|
||||
f.puts " static const struct rb_builtin_function #{table}[] = {"
|
||||
bs.each.with_index{|(func, (argc, cfunc_name)), i|
|
||||
f.puts " RB_BUILTIN_FUNCTION(#{i}, #{func}, #{cfunc_name}, #{argc}),"
|
||||
f.puts " RB_BUILTIN_FUNCTION(#{i}, #{func}, #{cfunc_name}, #{argc}, mjit_compile_invokebuiltin_for_#{func}),"
|
||||
}
|
||||
f.puts " RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0),"
|
||||
f.puts " RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0, 0),"
|
||||
f.puts " };"
|
||||
|
||||
f.puts
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
fprintf(f, " goto label_%lu;\n", arg.base_pos + else_offset);
|
||||
fprintf(f, " }\n");
|
||||
}
|
||||
% elsif insn.name == 'invokebuiltin' || insn.name == 'opt_invokebuiltin_delegate'
|
||||
{
|
||||
<%= render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
|
||||
}
|
||||
% else
|
||||
% # Before we `goto` next insn, we need to set return values, especially for getinlinecache
|
||||
% insn.rets.reverse_each.with_index do |ret, i|
|
||||
|
|
23
tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb
Normal file
23
tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb
Normal file
|
@ -0,0 +1,23 @@
|
|||
% # -*- C -*-
|
||||
% # Copyright (c) 2020 Urabe, Shyouhei. All rights reserved.
|
||||
% #
|
||||
% # This file is a part of the programming language Ruby. Permission is hereby
|
||||
% # granted, to either redistribute and/or modify this file, provided that the
|
||||
% # conditions mentioned in the file COPYING are met. Consult the file for
|
||||
% # details.
|
||||
%
|
||||
/* <%= insn.name %> */
|
||||
const struct rb_builtin_function *bf = (const void *)operands[0];
|
||||
%
|
||||
% if insn.name == 'invokebuiltin' then
|
||||
const rb_num_t index = -1;
|
||||
% else
|
||||
const rb_num_t index = (rb_num_t)operands[1];
|
||||
% end
|
||||
%
|
||||
if (bf->compiler) {
|
||||
bf->compiler(f, index);
|
||||
}
|
||||
else {
|
||||
mjit_invokebuiltin_default_compiler(f, bf, index);
|
||||
}
|
|
@ -67,13 +67,9 @@ switch (insn) {
|
|||
{
|
||||
% # opt_invokebuiltin_delegate_leave also implements leave insn. We need to handle it here for inlining.
|
||||
% if insn.name == 'opt_invokebuiltin_delegate_leave'
|
||||
RB_BUILTIN bf = (RB_BUILTIN)operands[0];
|
||||
rb_num_t index = (rb_num_t)operands[0];
|
||||
fprintf(f, "{\n");
|
||||
fprintf(f, " VALUE val;\n");
|
||||
fprintf(f, " RB_BUILTIN bf = (RB_BUILTIN)0x%"PRIxVALUE";\n", operands[0]);
|
||||
fprintf(f, " rb_num_t index = (rb_num_t)0x%"PRIxVALUE";\n", operands[1]);
|
||||
fprintf(f, <%= rstring2cstr(insn.expr.expr.lines.find { |l| l =~ / vm_invoke_builtin_delegate\(/ }).gsub("\n", '\n') %>);
|
||||
<%= render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
|
||||
fprintf(f, " stack[0] = val;\n");
|
||||
fprintf(f, "}\n");
|
||||
% else
|
||||
|
|
Loading…
Reference in a new issue