summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--benchmark/bm_hash_shift_u16.rb10
-rw-r--r--benchmark/bm_hash_shift_u24.rb10
-rw-r--r--benchmark/bm_hash_shift_u32.rb10
-rw-r--r--hash.c4
5 files changed, 37 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index c477363206..187e10f4f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Fri Dec 11 16:48:57 2015 Eric Wong <e@80x24.org>
+
+ * hash.c (rb_num_hash_start): avoid pathological behavior
+ [ruby-core:72028] [Feature #11405]
+
Fri Dec 11 11:58:46 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
* NEWS: Mentioned rubygems-2.5.1
diff --git a/benchmark/bm_hash_shift_u16.rb b/benchmark/bm_hash_shift_u16.rb
new file mode 100644
index 0000000000..ec800d0342
--- /dev/null
+++ b/benchmark/bm_hash_shift_u16.rb
@@ -0,0 +1,10 @@
+h = {}
+
+(16384..65536).each do |i|
+ h[i] = nil
+end
+
+300000.times do
+ k, v = h.shift
+ h[k] = v
+end
diff --git a/benchmark/bm_hash_shift_u24.rb b/benchmark/bm_hash_shift_u24.rb
new file mode 100644
index 0000000000..de4e0fa696
--- /dev/null
+++ b/benchmark/bm_hash_shift_u24.rb
@@ -0,0 +1,10 @@
+h = {}
+
+(0xff4000..0xffffff).each do |i|
+ h[i] = nil
+end
+
+300000.times do
+ k, v = h.shift
+ h[k] = v
+end
diff --git a/benchmark/bm_hash_shift_u32.rb b/benchmark/bm_hash_shift_u32.rb
new file mode 100644
index 0000000000..656aa55583
--- /dev/null
+++ b/benchmark/bm_hash_shift_u32.rb
@@ -0,0 +1,10 @@
+h = {}
+
+(0xffff4000..0xffffffff).each do |i|
+ h[i] = nil
+end
+
+300000.times do
+ k, v = h.shift
+ h[k] = v
+end
diff --git a/hash.c b/hash.c
index 52479c0ac2..927fcf7320 100644
--- a/hash.c
+++ b/hash.c
@@ -191,11 +191,11 @@ rb_num_hash_start(st_index_t n)
* - (n >> (RUBY_SPECIAL_SHIFT+3)) was added to make symbols hash well,
* n.b.: +3 to remove most ID scope, +1 worked well initially, too
* n.b.: +1 (instead of 3) worked well initially, too
- * - (n << 3) was finally added to avoid losing bits for fixnums
+ * - (n << 16) was finally added to avoid losing bits for fixnums
* - avoid expensive modulo instructions, it is currently only
* shifts and bitmask operations.
*/
- return (n >> (RUBY_SPECIAL_SHIFT + 3) | (n << 3)) ^ (n >> 3);
+ return (n >> (RUBY_SPECIAL_SHIFT + 3) ^ (n << 16)) ^ (n >> 3);
}
long