aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compile.c56
-rw-r--r--insns.def4
-rw-r--r--vm_insnhelper.c2
3 files changed, 44 insertions, 18 deletions
diff --git a/compile.c b/compile.c
index 71fecf1069..c16721e080 100644
--- a/compile.c
+++ b/compile.c
@@ -1743,27 +1743,57 @@ iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
static int
cdhash_cmp(VALUE val, VALUE lit)
{
- if (val == lit) return 0;
- if (SPECIAL_CONST_P(lit)) {
- return val != lit;
+ int tval, tlit;
+
+ if (val == lit) {
+ return 0;
}
- if (SPECIAL_CONST_P(val) || BUILTIN_TYPE(val) != BUILTIN_TYPE(lit)) {
- return -1;
+ else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
+ return val != lit;
+ }
+ else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
+ return -1;
+ }
+ else if (tlit != tval) {
+ return -1;
+ }
+ else if (tlit == T_SYMBOL) {
+ return val != lit;
+ }
+ else if (tlit == T_STRING) {
+ return rb_str_hash_cmp(lit, val);
}
- if (BUILTIN_TYPE(lit) == T_STRING) {
- return rb_str_hash_cmp(lit, val);
+ else if (tlit == T_BIGNUM) {
+ long x = FIX2LONG(rb_big_cmp(lit, val));
+
+ /* Given lit and val are both Bignum, x must be -1, 0, 1.
+ * There is no need to call rb_fix2int here. */
+ RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
+ return (int)x;
+ }
+ else if (tlit == T_FLOAT) {
+ return rb_float_cmp(lit, val);
+ }
+ else {
+ UNREACHABLE_RETURN(-1);
}
- return !rb_eql(lit, val);
}
static st_index_t
cdhash_hash(VALUE a)
{
- if (SPECIAL_CONST_P(a)) return (st_index_t)a;
- if (RB_TYPE_P(a, T_STRING)) return rb_str_hash(a);
- {
- VALUE hval = rb_hash(a);
- return (st_index_t)FIX2LONG(hval);
+ switch (OBJ_BUILTIN_TYPE(a)) {
+ case -1:
+ case T_SYMBOL:
+ return (st_index_t)a;
+ case T_STRING:
+ return rb_str_hash(a);
+ case T_BIGNUM:
+ return FIX2LONG(rb_big_hash(a));
+ case T_FLOAT:
+ return rb_dbl_long_hash(RFLOAT_VALUE(a));
+ default:
+ UNREACHABLE_RETURN(0);
}
}
diff --git a/insns.def b/insns.def
index cf9d980277..ced6054cce 100644
--- a/insns.def
+++ b/insns.def
@@ -1020,10 +1020,6 @@ opt_case_dispatch
(CDHASH hash, OFFSET else_offset)
(..., VALUE key)
()
-/* Case dispatch involves hash lookup, which inevitably compares
- * several objects each other. The same discussion to
- * opt_newarray_max also goes here. */
-// attr bool leaf = false; /* has rb_any_cmp() */
// attr rb_snum_t sp_inc = -1;
{
OFFSET dst = vm_case_dispatch(hash, else_offset, key);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 8d4b087874..50d95610c3 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3355,7 +3355,7 @@ vm_case_dispatch(CDHASH hash, OFFSET else_offset, VALUE key)
}
}
if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) {
- return FIX2INT((VALUE)val);
+ return FIX2LONG((VALUE)val);
}
else {
return else_offset;