diff options
author | Koichi Sasada <ko1@atdot.net> | 2021-02-13 05:37:46 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2021-02-13 11:51:33 +0900 |
commit | 813fe4c256f89babebb8ab53821ae5eb6bb138c6 (patch) | |
tree | d10671304bc5f7e3c70e0c9466bd33050f6e2c69 | |
parent | 81995797bb4d2db11635f716e9230206b1283ec7 (diff) | |
download | ruby-813fe4c256f89babebb8ab53821ae5eb6bb138c6.tar.gz |
opt_equality_by_mid for rb_equal_opt
This patch improves the performance of sequential and parallel
execution of rb_equal() (and rb_eql()).
[Bug #17497]
rb_equal_opt (and rb_eql_opt) does not have own cd and it waste
a time to initialize cd. This patch introduces opt_equality_by_mid()
to check equality without cd.
Furthermore, current master uses "static" cd on rb_equal_opt
(and rb_eql_opt) and it hurts CPU caches on multi-thread execution.
Now they are gone so there are no bottleneck on parallel execution.
-rw-r--r-- | vm_insnhelper.c | 99 |
1 files changed, 63 insertions, 36 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c index a0e6a522d6..4d9e7802eb 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1854,6 +1854,7 @@ check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)()) static inline int vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, VALUE (*func)()) { + VM_ASSERT(iseq != NULL); const struct rb_callcache *cc = vm_search_method((VALUE)iseq, cd, recv); return check_cfunc(vm_cc_cme(cc), func); } @@ -1890,7 +1891,7 @@ FLONUM_2_P(VALUE a, VALUE b) } static VALUE -opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd) +opt_equality_specialized(VALUE recv, VALUE obj) { if (FIXNUM_2_P(recv, obj) && EQ_UNREDEFINED_P(INTEGER)) { goto compare_by_identity; @@ -1902,7 +1903,7 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd) goto compare_by_identity; } else if (SPECIAL_CONST_P(recv)) { - goto compare_by_funcall; + // } else if (RBASIC_CLASS(recv) == rb_cFloat && RB_FLOAT_TYPE_P(obj) && EQ_UNREDEFINED_P(FLOAT)) { double a = RFLOAT_VALUE(recv); @@ -1932,11 +1933,7 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd) return rb_str_eql_internal(obj, recv); } } - - compare_by_funcall: - if (! vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) { - return Qundef; - } + return Qundef; compare_by_identity: if (recv == obj) { @@ -1947,47 +1944,77 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd) } } +static VALUE +opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd) +{ + VM_ASSERT(cd_owner != NULL); + + VALUE val = opt_equality_specialized(recv, obj); + if (val != Qundef) return val; + + if (!vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) { + return Qundef; + } + else { + if (recv == obj) { + return Qtrue; + } + else { + return Qfalse; + } + } +} + #undef EQ_UNREDEFINED_P #ifndef MJIT_HEADER -VALUE -rb_equal_opt(VALUE obj1, VALUE obj2) + +static inline const struct rb_callcache *gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, int argc); // vm_eval.c +NOINLINE(static VALUE opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid)); + +static VALUE +opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid) { - STATIC_ASSERT(idEq_is_embeddable, VM_CI_EMBEDDABLE_P(idEq, 0, 1, 0)); + const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, 1); -#if USE_EMBED_CI - static struct rb_call_data cd = { - .ci = vm_ci_new_id(idEq, 0, 1, 0), - }; -#else - struct rb_call_data cd = { - .ci = &VM_CI_ON_STACK(idEq, 0, 1, 0), - }; -#endif + if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) { + if (recv == obj) { + return Qtrue; + } + else { + return Qfalse; + } + } + else { + return Qundef; + } +} - cd.cc = &vm_empty_cc; - return opt_equality(NULL, obj1, obj2, &cd); +static VALUE +opt_equality_by_mid(VALUE recv, VALUE obj, ID mid) +{ + VALUE val = opt_equality_specialized(recv, obj); + if (val != Qundef) { + return val; + } + else { + return opt_equality_by_mid_slowpath(recv, obj, mid); + } } VALUE -rb_eql_opt(VALUE obj1, VALUE obj2) +rb_equal_opt(VALUE obj1, VALUE obj2) { - STATIC_ASSERT(idEqlP_is_embeddable, VM_CI_EMBEDDABLE_P(idEqlP, 0, 1, 0)); - -#if USE_EMBED_CI - static struct rb_call_data cd = { - .ci = vm_ci_new_id(idEqlP, 0, 1, 0), - }; -#else - struct rb_call_data cd = { - .ci = &VM_CI_ON_STACK(idEqlP, 0, 1, 0), - }; -#endif + return opt_equality_by_mid(obj1, obj2, idEq); +} - cd.cc = &vm_empty_cc; - return opt_equality(NULL, obj1, obj2, &cd); +VALUE +rb_eql_opt(VALUE obj1, VALUE obj2) +{ + return opt_equality_by_mid(obj1, obj2, idEqlP); } -#endif + +#endif // MJIT_HEADER extern VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *, int kw_splat); |