summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2021-02-13 05:37:46 +0900
committerKoichi Sasada <ko1@atdot.net>2021-02-13 11:51:33 +0900
commit813fe4c256f89babebb8ab53821ae5eb6bb138c6 (patch)
treed10671304bc5f7e3c70e0c9466bd33050f6e2c69 /vm_insnhelper.c
parent81995797bb4d2db11635f716e9230206b1283ec7 (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4177
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c99
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);