ruby-changes:69819
From: Koichi <ko1@a...>
Date: Fri, 19 Nov 2021 08:32:49 +0900 (JST)
Subject: [ruby-changes:69819] 82ea287018 (master): optimize `Struct` getter/setter
https://git.ruby-lang.org/ruby.git/commit/?id=82ea287018 From 82ea2870188d66aa75a99f03b4e7fdd1750aa196 Mon Sep 17 00:00:00 2001 From: Koichi Sasada <ko1@a...> Date: Thu, 18 Nov 2021 11:01:31 +0900 Subject: optimize `Struct` getter/setter Introduce new optimized method type `OPTIMIZED_METHOD_TYPE_STRUCT_AREF/ASET` with index information. --- common.mk | 1 + compile.c | 95 ------------------------ debug_counter.h | 2 + method.h | 3 + proc.c | 6 ++ struct.c | 70 ++---------------- test/ruby/test_yjit.rb | 2 + vm_eval.c | 39 ++++++---- vm_insnhelper.c | 196 ++++++++++++++++++++++++++++++++++--------------- vm_method.c | 5 +- 10 files changed, 181 insertions(+), 238 deletions(-) diff --git a/common.mk b/common.mk index ebf98993f64..7ba32ac6e8f 100644 --- a/common.mk +++ b/common.mk @@ -16068,6 +16068,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h https://github.com/ruby/ruby/blob/trunk/common.mk#L16068 vm.$(OBJEXT): $(top_srcdir)/internal/serial.h vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm.$(OBJEXT): $(top_srcdir)/internal/string.h +vm.$(OBJEXT): $(top_srcdir)/internal/struct.h vm.$(OBJEXT): $(top_srcdir)/internal/symbol.h vm.$(OBJEXT): $(top_srcdir)/internal/thread.h vm.$(OBJEXT): $(top_srcdir)/internal/variable.h diff --git a/compile.c b/compile.c index 2b92893d801..a6505f82d6d 100644 --- a/compile.c +++ b/compile.c @@ -10588,101 +10588,6 @@ rb_local_defined(ID id, const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L10588 return 0; } -static int -caller_location(VALUE *path, VALUE *realpath) -{ - const rb_execution_context_t *ec = GET_EC(); - const rb_control_frame_t *const cfp = - rb_vm_get_ruby_level_next_cfp(ec, ec->cfp); - - if (cfp) { - int line = rb_vm_get_sourceline(cfp); - *path = rb_iseq_path(cfp->iseq); - *realpath = rb_iseq_realpath(cfp->iseq); - return line; - } - else { - *path = rb_fstring_lit("<compiled>"); - *realpath = *path; - return 1; - } -} - -typedef struct { - VALUE arg; - VALUE func; - int line; -} accessor_args; - -static const rb_iseq_t * -method_for_self(VALUE name, VALUE arg, const struct rb_builtin_function *func, - void (*build)(rb_iseq_t *, LINK_ANCHOR *, const void *)) -{ - VALUE path, realpath; - accessor_args acc; - - acc.arg = arg; - acc.func = (VALUE)func; - acc.line = caller_location(&path, &realpath); - struct rb_iseq_new_with_callback_callback_func *ifunc = - rb_iseq_new_with_callback_new_callback(build, &acc); - return rb_iseq_new_with_callback(ifunc, - rb_sym2str(name), path, realpath, - INT2FIX(acc.line), 0, ISEQ_TYPE_METHOD, 0); -} - -static void -for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a) -{ - const accessor_args *const args = (void *)a; - const int line = args->line; - struct rb_iseq_constant_body *const body = iseq->body; - - iseq_set_local_table(iseq, 0); - body->param.lead_num = 0; - body->param.size = 0; - - NODE dummy_line_node = generate_dummy_line_node(line, -1); - ADD_INSN1(ret, &dummy_line_node, putobject, args->arg); - ADD_INSN1(ret, &dummy_line_node, invokebuiltin, args->func); -} - -static void -for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a) -{ - const accessor_args *const args = (void *)a; - const int line = args->line; - struct rb_iseq_constant_body *const body = iseq->body; - static const ID vars[] = {1, idUScore}; - - iseq_set_local_table(iseq, vars); - body->param.lead_num = 1; - body->param.size = 1; - - NODE dummy_line_node = generate_dummy_line_node(line, -1); - ADD_GETLOCAL(ret, &dummy_line_node, numberof(vars)-1, 0); - ADD_INSN1(ret, &dummy_line_node, putobject, args->arg); - ADD_INSN1(ret, &dummy_line_node, invokebuiltin, args->func); -} - -/* - * func (index) -> (value) - */ -const rb_iseq_t * -rb_method_for_self_aref(VALUE name, VALUE arg, const struct rb_builtin_function *func) -{ - return method_for_self(name, arg, func, for_self_aref); -} - -/* - * func (index, value) -> (value) - */ -const rb_iseq_t * -rb_method_for_self_aset(VALUE name, VALUE arg, const struct rb_builtin_function *func) -{ - return method_for_self(name, arg, func, for_self_aset); -} - /* ISeq binary format */ #ifndef IBF_ISEQ_DEBUG diff --git a/debug_counter.h b/debug_counter.h index 3cf80cc188b..3f0dec948fa 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -97,6 +97,8 @@ RB_DEBUG_COUNTER(ccf_bmethod) https://github.com/ruby/ruby/blob/trunk/debug_counter.h#L97 RB_DEBUG_COUNTER(ccf_opt_send) RB_DEBUG_COUNTER(ccf_opt_call) RB_DEBUG_COUNTER(ccf_opt_block_call) +RB_DEBUG_COUNTER(ccf_opt_struct_aref) +RB_DEBUG_COUNTER(ccf_opt_struct_aset) RB_DEBUG_COUNTER(ccf_super_method) /* diff --git a/method.h b/method.h index b7c4318f830..031d2ce89f3 100644 --- a/method.h +++ b/method.h @@ -167,11 +167,14 @@ enum method_optimized_type { https://github.com/ruby/ruby/blob/trunk/method.h#L167 OPTIMIZED_METHOD_TYPE_SEND, OPTIMIZED_METHOD_TYPE_CALL, OPTIMIZED_METHOD_TYPE_BLOCK_CALL, + OPTIMIZED_METHOD_TYPE_STRUCT_AREF, + OPTIMIZED_METHOD_TYPE_STRUCT_ASET, OPTIMIZED_METHOD_TYPE__MAX }; typedef struct rb_method_optimized { enum method_optimized_type type; + unsigned int index; } rb_method_optimized_t; struct rb_method_definition_struct { diff --git a/proc.c b/proc.c index 9c62abb0c63..13996b102ad 100644 --- a/proc.c +++ b/proc.c @@ -2681,6 +2681,12 @@ rb_method_entry_min_max_arity(const rb_method_entry_t *me, int *max) https://github.com/ruby/ruby/blob/trunk/proc.c#L2681 case OPTIMIZED_METHOD_TYPE_BLOCK_CALL: *max = UNLIMITED_ARGUMENTS; return 0; + case OPTIMIZED_METHOD_TYPE_STRUCT_AREF: + *max = 0; + return 0; + case OPTIMIZED_METHOD_TYPE_STRUCT_ASET: + *max = 1; + return 0; default: break; } diff --git a/struct.c b/struct.c index ad8b480d8d1..2f296b34f62 100644 --- a/struct.c +++ b/struct.c @@ -28,9 +28,6 @@ enum { https://github.com/ruby/ruby/blob/trunk/struct.c#L28 AREF_HASH_THRESHOLD = 10 }; -const rb_iseq_t *rb_method_for_self_aref(VALUE name, VALUE arg, const struct rb_builtin_function *func); -const rb_iseq_t *rb_method_for_self_aset(VALUE name, VALUE arg, const struct rb_builtin_function *func); - VALUE rb_cStruct; static ID id_members, id_back_members, id_keyword_init; @@ -229,32 +226,6 @@ rb_struct_getmember(VALUE obj, ID id) https://github.com/ruby/ruby/blob/trunk/struct.c#L226 UNREACHABLE_RETURN(Qnil); } -static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_GET(obj, 0);} -static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_GET(obj, 1);} -static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_GET(obj, 2);} -static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_GET(obj, 3);} -static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_GET(obj, 4);} -static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_GET(obj, 5);} -static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_GET(obj, 6);} -static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_GET(obj, 7);} -static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_GET(obj, 8);} -static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_GET(obj, 9);} - -#define N_REF_FUNC numberof(ref_func) - -static VALUE (*const ref_func[])(VALUE) = { - rb_struct_ref0, - rb_struct_ref1, - rb_struct_ref2, - rb_struct_ref3, - rb_struct_ref4, - rb_struct_ref5, - rb_struct_ref6, - rb_struct_ref7, - rb_struct_ref8, - rb_struct_ref9, -}; - static void rb_struct_modify(VALUE s) { @@ -300,42 +271,16 @@ struct_pos_num(VALUE s, VALUE idx) https://github.com/ruby/ruby/blob/trunk/struct.c#L271 return i; } -static VALUE -opt_struct_aref(rb_execution_context_t *ec, VALUE self, VALUE idx) -{ - long i = struct_pos_num(self, idx); - return RSTRUCT_GET(self, i); -} - -static VALUE -opt_struct_aset(rb_execution_context_t *ec, VALUE self, VALUE val, VALUE idx) -{ - long i = struct_pos_num(self, idx); - rb_struct_modify(self); - RSTRUCT_SET(self, i, val); - return val; -} - -static const struct rb_builtin_function struct_aref_builtin = - 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, 0); - static void define_aref_method(VALUE nstr, VALUE name, VALUE off) { - const rb_iseq_t *iseq = rb_method_for_self_aref(name, off, &struct_aref_builtin); - iseq->body->builtin_inline_p = true; - - rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, METHOD_VISI_PUBLIC); + rb_add_method_optimized(nstr, SYM2ID(name), OPTIMIZED_METHOD_TYPE_STRUCT_AREF, FIX2UINT(off), METHOD_VISI_PUBLIC); } static void define_aset_method(VALUE nstr, VALUE name, VALUE off) { - const rb_iseq_t *iseq = rb_method_for_self_aset(name, off, &struct_aset_builtin); - - rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, METHOD_VISI_PUBLIC); + rb_add_method_optimized(nstr, SYM2ID(name), OPTIMIZED_METHOD_TYPE_STRUCT_ASET, FIX2UINT(off), METHOD_VISI_PUBLIC); } static VALUE @@ -386,13 +331,8 @@ setup_struct(VALUE nstr, VALUE members) https://github.com/ruby/ruby/blob/trunk/struct.c#L331 ID id = SYM2ID(sym); VALUE off = LONG2NUM(i); - if (i < N_REF_FUNC) { - rb_define_method_id(nstr, id, ref_func[i], 0); - } - else { - define_aref_method(nstr, sym, off); - } - define_aset_method(nstr, ID2SYM(rb_id_attrset(id)), off); + define_aref_method(nstr, sym, off); + define_aset_method(nstr, ID2SYM(rb_id_attrset(id)), off); } return nstr; @@ -844,7 +784,7 @@ rb_struct_alloc(VALUE klass, VALUE values) https://github.com/ruby/ruby/blob/trunk/struct.c#L784 VALUE rb_struct_new(VALUE klass, ...) { - VALUE tmpargs[N_REF_FUNC], *mem = tmpargs; + VALUE tmpargs[16], * (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/