From f6b94f0cba4f58722858fe680bfad4a859ccaa09 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Jun 2022 17:27:56 -0700 Subject: [PATCH] Emit special instruction for array literal + .hash This commit introduces a new instruction `opt_newarray_hash` which is used when there is an array literal with a `.hash` method called on the literal. For example: ``` [a, b, c].hash ``` Will emit an `opt_newarray_hash` instruction. This instruction falls back to a method call if the hash method has been monkeypatched, similar to `opt_newarray_min`. Co-authored-by: John Hawthorn --- array.c | 30 ++++++++++++++++++------------ compile.c | 4 ++++ defs/id.def | 1 + insns.def | 12 ++++++++++++ internal/array.h | 1 + vm.c | 1 + vm_core.h | 1 + vm_insnhelper.c | 12 ++++++++++++ 8 files changed, 50 insertions(+), 12 deletions(-) diff --git a/array.c b/array.c index 7b3f5bd0b0..e714652520 100644 --- a/array.c +++ b/array.c @@ -5306,6 +5306,23 @@ rb_ary_eql(VALUE ary1, VALUE ary2) return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } +VALUE +rb_ary_hash_values(long len, const VALUE *elements) +{ + long i; + st_index_t h; + VALUE n; + + h = rb_hash_start(len); + h = rb_hash_uint(h, (st_index_t)rb_ary_hash_values); + for (i=0; i integer @@ -5322,18 +5339,7 @@ rb_ary_eql(VALUE ary1, VALUE ary2) static VALUE rb_ary_hash(VALUE ary) { - long i; - st_index_t h; - VALUE n; - - h = rb_hash_start(RARRAY_LEN(ary)); - h = rb_hash_uint(h, (st_index_t)rb_ary_hash); - for (i=0; iinsn_id = BIN(opt_newarray_min); ELEM_REMOVE(&niobj->link); return COMPILE_OK; + case idHash: + iobj->insn_id = BIN(opt_newarray_hash); + ELEM_REMOVE(&niobj->link); + return COMPILE_OK; } } } diff --git a/defs/id.def b/defs/id.def index 097e34e405..1ce6710094 100644 --- a/defs/id.def +++ b/defs/id.def @@ -2,6 +2,7 @@ firstline, predefined = __LINE__+1, %[\ max min + hash freeze nil? inspect diff --git a/insns.def b/insns.def index b5dea9c10c..cac1bf372d 100644 --- a/insns.def +++ b/insns.def @@ -867,6 +867,18 @@ opt_newarray_min val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num)); } +DEFINE_INSN +opt_newarray_hash +(rb_num_t num) +(...) +(VALUE val) +/* Same discussion as opt_newarray_max. */ +// attr bool leaf = false; /* has rb_funcall() */ +// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num; +{ + val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num)); +} + /* super(args) # args.size => num */ DEFINE_INSN invokesuper diff --git a/internal/array.h b/internal/array.h index 60f66f31bf..acd286941d 100644 --- a/internal/array.h +++ b/internal/array.h @@ -21,6 +21,7 @@ #define RARRAY_PTR_IN_USE_FLAG FL_USER14 /* array.c */ +VALUE rb_ary_hash_values(long len, const VALUE *elements); VALUE rb_ary_last(int, const VALUE *, VALUE); void rb_ary_set_len(VALUE, long); void rb_ary_delete_same(VALUE, VALUE); diff --git a/vm.c b/vm.c index 76041b0b91..7204d5171d 100644 --- a/vm.c +++ b/vm.c @@ -1969,6 +1969,7 @@ vm_init_redefined_flag(void) OP(UMinus, UMINUS), (C(String)); OP(Max, MAX), (C(Array)); OP(Min, MIN), (C(Array)); + OP(Hash, HASH), (C(Array)); OP(Call, CALL), (C(Proc)); OP(And, AND), (C(Integer)); OP(Or, OR), (C(Integer)); diff --git a/vm_core.h b/vm_core.h index 2fca0aecd2..f93b191262 100644 --- a/vm_core.h +++ b/vm_core.h @@ -576,6 +576,7 @@ enum ruby_basic_operators { BOP_UMINUS, BOP_MAX, BOP_MIN, + BOP_HASH, BOP_CALL, BOP_AND, BOP_OR, diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 1e40088ffa..b409cf509b 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -4922,6 +4922,18 @@ vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr) } } +static VALUE +vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr) +{ + // If Array#hash is _not_ monkeypatched, use the optimized call + if (BASIC_OP_UNREDEFINED_P(BOP_HASH, ARRAY_REDEFINED_OP_FLAG)) { + return rb_ary_hash_values(num, ptr); + } + else { + return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idHash, 0, NULL, RB_NO_KEYWORDS); + } +} + #undef id_cmp #define IMEMO_CONST_CACHE_SHAREABLE IMEMO_FL_USER0 -- 2.36.0