Skip to content

Commit 813fe4c

Browse files
committed
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.
1 parent 8199579 commit 813fe4c

File tree

1 file changed

+63
-36
lines changed

1 file changed

+63
-36
lines changed

vm_insnhelper.c

Lines changed: 63 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,7 @@ check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)())
18541854
static inline int
18551855
vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, VALUE (*func)())
18561856
{
1857+
VM_ASSERT(iseq != NULL);
18571858
const struct rb_callcache *cc = vm_search_method((VALUE)iseq, cd, recv);
18581859
return check_cfunc(vm_cc_cme(cc), func);
18591860
}
@@ -1890,7 +1891,7 @@ FLONUM_2_P(VALUE a, VALUE b)
18901891
}
18911892

18921893
static VALUE
1893-
opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
1894+
opt_equality_specialized(VALUE recv, VALUE obj)
18941895
{
18951896
if (FIXNUM_2_P(recv, obj) && EQ_UNREDEFINED_P(INTEGER)) {
18961897
goto compare_by_identity;
@@ -1902,7 +1903,7 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
19021903
goto compare_by_identity;
19031904
}
19041905
else if (SPECIAL_CONST_P(recv)) {
1905-
goto compare_by_funcall;
1906+
//
19061907
}
19071908
else if (RBASIC_CLASS(recv) == rb_cFloat && RB_FLOAT_TYPE_P(obj) && EQ_UNREDEFINED_P(FLOAT)) {
19081909
double a = RFLOAT_VALUE(recv);
@@ -1932,11 +1933,7 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
19321933
return rb_str_eql_internal(obj, recv);
19331934
}
19341935
}
1935-
1936-
compare_by_funcall:
1937-
if (! vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) {
1938-
return Qundef;
1939-
}
1936+
return Qundef;
19401937

19411938
compare_by_identity:
19421939
if (recv == obj) {
@@ -1947,47 +1944,77 @@ opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
19471944
}
19481945
}
19491946

1947+
static VALUE
1948+
opt_equality(const rb_iseq_t *cd_owner, VALUE recv, VALUE obj, CALL_DATA cd)
1949+
{
1950+
VM_ASSERT(cd_owner != NULL);
1951+
1952+
VALUE val = opt_equality_specialized(recv, obj);
1953+
if (val != Qundef) return val;
1954+
1955+
if (!vm_method_cfunc_is(cd_owner, cd, recv, rb_obj_equal)) {
1956+
return Qundef;
1957+
}
1958+
else {
1959+
if (recv == obj) {
1960+
return Qtrue;
1961+
}
1962+
else {
1963+
return Qfalse;
1964+
}
1965+
}
1966+
}
1967+
19501968
#undef EQ_UNREDEFINED_P
19511969

19521970
#ifndef MJIT_HEADER
1953-
VALUE
1954-
rb_equal_opt(VALUE obj1, VALUE obj2)
1971+
1972+
static inline const struct rb_callcache *gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, int argc); // vm_eval.c
1973+
NOINLINE(static VALUE opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid));
1974+
1975+
static VALUE
1976+
opt_equality_by_mid_slowpath(VALUE recv, VALUE obj, ID mid)
19551977
{
1956-
STATIC_ASSERT(idEq_is_embeddable, VM_CI_EMBEDDABLE_P(idEq, 0, 1, 0));
1978+
const struct rb_callcache *cc = gccct_method_search(GET_EC(), recv, mid, 1);
19571979

1958-
#if USE_EMBED_CI
1959-
static struct rb_call_data cd = {
1960-
.ci = vm_ci_new_id(idEq, 0, 1, 0),
1961-
};
1962-
#else
1963-
struct rb_call_data cd = {
1964-
.ci = &VM_CI_ON_STACK(idEq, 0, 1, 0),
1965-
};
1966-
#endif
1980+
if (cc && check_cfunc(vm_cc_cme(cc), rb_obj_equal)) {
1981+
if (recv == obj) {
1982+
return Qtrue;
1983+
}
1984+
else {
1985+
return Qfalse;
1986+
}
1987+
}
1988+
else {
1989+
return Qundef;
1990+
}
1991+
}
19671992

1968-
cd.cc = &vm_empty_cc;
1969-
return opt_equality(NULL, obj1, obj2, &cd);
1993+
static VALUE
1994+
opt_equality_by_mid(VALUE recv, VALUE obj, ID mid)
1995+
{
1996+
VALUE val = opt_equality_specialized(recv, obj);
1997+
if (val != Qundef) {
1998+
return val;
1999+
}
2000+
else {
2001+
return opt_equality_by_mid_slowpath(recv, obj, mid);
2002+
}
19702003
}
19712004

19722005
VALUE
1973-
rb_eql_opt(VALUE obj1, VALUE obj2)
2006+
rb_equal_opt(VALUE obj1, VALUE obj2)
19742007
{
1975-
STATIC_ASSERT(idEqlP_is_embeddable, VM_CI_EMBEDDABLE_P(idEqlP, 0, 1, 0));
1976-
1977-
#if USE_EMBED_CI
1978-
static struct rb_call_data cd = {
1979-
.ci = vm_ci_new_id(idEqlP, 0, 1, 0),
1980-
};
1981-
#else
1982-
struct rb_call_data cd = {
1983-
.ci = &VM_CI_ON_STACK(idEqlP, 0, 1, 0),
1984-
};
1985-
#endif
2008+
return opt_equality_by_mid(obj1, obj2, idEq);
2009+
}
19862010

1987-
cd.cc = &vm_empty_cc;
1988-
return opt_equality(NULL, obj1, obj2, &cd);
2011+
VALUE
2012+
rb_eql_opt(VALUE obj1, VALUE obj2)
2013+
{
2014+
return opt_equality_by_mid(obj1, obj2, idEqlP);
19892015
}
1990-
#endif
2016+
2017+
#endif // MJIT_HEADER
19912018

19922019
extern VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *, int kw_splat);
19932020

0 commit comments

Comments
 (0)