merge revision(s) 49376,49387,49389: [Backport #10761]

* st.c (st_numhash): mix float value for flonum

	* hash.c (rb_any_hash): ditto

	* benchmark/bm_hash_aref_flo.rb: new benchmark

	* benchmark/bm_hash_ident_flo.rb: ditto
	  [Bug #10761]

	* benchmark/bm_marshal_dump_flo.rb: new benchmark for [Bug #10761]

	* marshal.c (w_object, marshal_dump): use indetity tables for
	  arbitrary VALUE keys, because of performance of FLONUM.
	  [Bug #10761]

	* marshal.c (obj_alloc_by_klass, marshal_load): ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@49513 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
naruse 2015-02-05 16:05:10 +00:00
parent b5623f9863
commit 665f7a2ff1
9 changed files with 67 additions and 8 deletions

View file

@ -1,3 +1,23 @@
Fri Feb 6 01:03:38 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* marshal.c (w_object, marshal_dump): use indetity tables for
arbitrary VALUE keys, because of performance of FLONUM.
[Bug #10761]
* marshal.c (obj_alloc_by_klass, marshal_load): ditto.
Fri Feb 6 01:03:38 2015 Eric Wong <e@80x24.org>
* benchmark/bm_marshal_dump_flo.rb: new benchmark for [Bug #10761]
Fri Feb 6 01:03:38 2015 Eric Wong <e@80x24.org>
* st.c (st_numhash): mix float value for flonum
* hash.c (rb_any_hash): ditto
* benchmark/bm_hash_aref_flo.rb: new benchmark
* benchmark/bm_hash_ident_flo.rb: ditto
[Bug #10761]
Thu Feb 5 16:30:09 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> Thu Feb 5 16:30:09 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (gettable_gen): disable warnings of possible reference * parse.y (gettable_gen): disable warnings of possible reference

View file

@ -0,0 +1,4 @@
h = {}
strs = (1..10000).to_a.map!(&:to_f)
strs.each { |s| h[s] = s }
50.times { strs.each { |s| h[s] } }

View file

@ -0,0 +1,4 @@
h = {}.compare_by_identity
strs = (1..10000).to_a.map!(&:to_f)
strs.each { |s| h[s] = s }
50.times { strs.each { |s| h[s] } }

View file

@ -0,0 +1,2 @@
bug10761 = 10000.times.map { |x| x.to_f }
100.times { Marshal.dump(bug10761) }

20
hash.c
View file

@ -137,7 +137,13 @@ rb_any_hash(VALUE a)
if (SPECIAL_CONST_P(a)) { if (SPECIAL_CONST_P(a)) {
if (a == Qundef) return 0; if (a == Qundef) return 0;
if (STATIC_SYM_P(a)) a >>= (RUBY_SPECIAL_SHIFT + ID_SCOPE_SHIFT); if (STATIC_SYM_P(a)) {
a >>= (RUBY_SPECIAL_SHIFT + ID_SCOPE_SHIFT);
}
else if (FLONUM_P(a)) {
/* prevent pathological behavior: [Bug #10761] */
a = (st_index_t)rb_float_value(a);
}
hnum = rb_objid_hash((st_index_t)a); hnum = rb_objid_hash((st_index_t)a);
} }
else if (BUILTIN_TYPE(a) == T_STRING) { else if (BUILTIN_TYPE(a) == T_STRING) {
@ -2501,6 +2507,18 @@ rb_hash_compare_by_id_p(VALUE hash)
return Qfalse; return Qfalse;
} }
st_table *
rb_init_identtable(void)
{
return st_init_table(&identhash);
}
st_table *
rb_init_identtable_with_size(st_index_t size)
{
return st_init_table_with_size(&identhash, size);
}
static int static int
any_p_i(VALUE key, VALUE value, VALUE arg) any_p_i(VALUE key, VALUE value, VALUE arg)
{ {

View file

@ -701,6 +701,8 @@ struct st_table *rb_hash_tbl_raw(VALUE hash);
VALUE rb_hash_has_key(VALUE hash, VALUE key); VALUE rb_hash_has_key(VALUE hash, VALUE key);
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
long rb_objid_hash(st_index_t index); long rb_objid_hash(st_index_t index);
st_table *rb_init_identtable(void);
st_table *rb_init_identtable_with_size(st_index_t size);
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h) #define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h)
VALUE rb_hash_keys(VALUE hash); VALUE rb_hash_keys(VALUE hash);

View file

@ -751,7 +751,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
VALUE real_obj = obj; VALUE real_obj = obj;
obj = compat->dumper(real_obj); obj = compat->dumper(real_obj);
if (!arg->compat_tbl) { if (!arg->compat_tbl) {
arg->compat_tbl = st_init_numtable(); arg->compat_tbl = rb_init_identtable();
} }
st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
if (obj != real_obj && !ivtbl) hasiv = 0; if (obj != real_obj && !ivtbl) hasiv = 0;
@ -1000,7 +1000,7 @@ marshal_dump(int argc, VALUE *argv)
wrapper = TypedData_Make_Struct(rb_cData, struct dump_arg, &dump_arg_data, arg); wrapper = TypedData_Make_Struct(rb_cData, struct dump_arg, &dump_arg_data, arg);
arg->dest = 0; arg->dest = 0;
arg->symbols = st_init_numtable(); arg->symbols = st_init_numtable();
arg->data = st_init_numtable(); arg->data = rb_init_identtable();
arg->infection = 0; arg->infection = 0;
arg->compat_tbl = 0; arg->compat_tbl = 0;
arg->encodings = 0; arg->encodings = 0;
@ -1510,7 +1510,7 @@ obj_alloc_by_klass(VALUE klass, struct load_arg *arg, VALUE *oldclass)
if (oldclass) *oldclass = compat->oldclass; if (oldclass) *oldclass = compat->oldclass;
if (!arg->compat_tbl) { if (!arg->compat_tbl) {
arg->compat_tbl = st_init_numtable(); arg->compat_tbl = rb_init_identtable();
} }
st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
return obj; return obj;
@ -2019,7 +2019,7 @@ marshal_load(int argc, VALUE *argv)
arg->src = port; arg->src = port;
arg->offset = 0; arg->offset = 0;
arg->symbols = st_init_numtable(); arg->symbols = st_init_numtable();
arg->data = st_init_numtable(); arg->data = rb_init_identtable();
arg->compat_tbl = 0; arg->compat_tbl = 0;
arg->proc = 0; arg->proc = 0;
arg->readable = 0; arg->readable = 0;

9
st.c
View file

@ -1761,6 +1761,15 @@ st_numhash(st_data_t n)
* - (n << 3) was finally added to avoid losing bits for fixnums * - (n << 3) was finally added to avoid losing bits for fixnums
* - avoid expensive modulo instructions, it is currently only * - avoid expensive modulo instructions, it is currently only
* shifts and bitmask operations. * shifts and bitmask operations.
* - flonum (on 64-bit) is pathologically bad, mix the actual
* float value in, but do not use the float value as-is since
* many integers get interpreted as 2.0 or -2.0 [Bug #10761]
*/ */
#ifdef USE_FLONUM /* RUBY */
if (FLONUM_P(n)) {
n ^= (st_data_t)rb_float_value(n);
}
#endif
return (st_index_t)((n>>(RUBY_SPECIAL_SHIFT+3)|(n<<3)) ^ (n>>3)); return (st_index_t)((n>>(RUBY_SPECIAL_SHIFT+3)|(n<<3)) ^ (n>>3));
} }

View file

@ -1,10 +1,10 @@
#define RUBY_VERSION "2.2.0" #define RUBY_VERSION "2.2.0"
#define RUBY_RELEASE_DATE "2015-02-05" #define RUBY_RELEASE_DATE "2015-02-06"
#define RUBY_PATCHLEVEL 38 #define RUBY_PATCHLEVEL 39
#define RUBY_RELEASE_YEAR 2015 #define RUBY_RELEASE_YEAR 2015
#define RUBY_RELEASE_MONTH 2 #define RUBY_RELEASE_MONTH 2
#define RUBY_RELEASE_DAY 5 #define RUBY_RELEASE_DAY 6
#include "ruby/version.h" #include "ruby/version.h"