libgo patch committed: Return random number of hash of NaN

Submitted by Ian Taylor on Sept. 22, 2012, 6:06 a.m.

Details

Message ID mcrpq5eoakg.fsf@google.com
State New
Headers show

Commit Message

Ian Taylor Sept. 22, 2012, 6:06 a.m.
It is valid to store a NaN in a Go hash table.  However, the result can
not be looked up, because NaN never equals NaN.  The only way to see the
result is to range over the map.  This means that the hash code used for
a NaN is irrelevant.  In general it's better to not hash all NaN values
to the same bucket, so this patch simply uses a random number.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline and 4.7 branch.

Ian

Patch hide | download patch | download mbox

diff -r 895a5e834a7b libgo/runtime/go-type-complex.c
--- a/libgo/runtime/go-type-complex.c	Fri Sep 21 23:01:55 2012 -0700
+++ b/libgo/runtime/go-type-complex.c	Fri Sep 21 23:03:04 2012 -0700
@@ -32,10 +32,14 @@ 
       cf = ucf.cf;
       cfr = __builtin_crealf (cf);
       cfi = __builtin_cimagf (cf);
-      if (__builtin_isinff (cfr) || __builtin_isinff (cfi)
-	  || __builtin_isnanf (cfr) || __builtin_isnanf (cfi))
+      if (__builtin_isinff (cfr) || __builtin_isinff (cfi))
 	return 0;
 
+      /* NaN != NaN, so the hash code of a NaN is irrelevant.  Make it
+	 random so that not all NaNs wind up in the same place.  */
+      if (__builtin_isnanf (cfr) || __builtin_isnanf (cfi))
+	return runtime_fastrand1 ();
+
       /* Avoid negative zero.  */
       if (cfr == 0 && cfi == 0)
 	return 0;
@@ -62,10 +66,12 @@ 
       cd = ucd.cd;
       cdr = __builtin_crealf (cd);
       cdi = __builtin_cimagf (cd);
-      if (__builtin_isinf (cdr) || __builtin_isinf (cdi)
-	  || __builtin_isnan (cdr) || __builtin_isnan (cdi))
+      if (__builtin_isinf (cdr) || __builtin_isinf (cdi))
 	return 0;
 
+      if (__builtin_isnan (cdr) || __builtin_isnan (cdi))
+	return runtime_fastrand1 ();
+
       /* Avoid negative zero.  */
       if (cdr == 0 && cdi == 0)
 	return 0;
diff -r 895a5e834a7b libgo/runtime/go-type-float.c
--- a/libgo/runtime/go-type-float.c	Fri Sep 21 23:01:55 2012 -0700
+++ b/libgo/runtime/go-type-float.c	Fri Sep 21 23:03:04 2012 -0700
@@ -29,8 +29,14 @@ 
 
       __builtin_memcpy (uf.a, vkey, 4);
       f = uf.f;
-      if (__builtin_isinff (f) || __builtin_isnanf (f) || f == 0)
+      if (__builtin_isinff (f) || f == 0)
 	return 0;
+
+      /* NaN != NaN, so the hash code of a NaN is irrelevant.  Make it
+	 random so that not all NaNs wind up in the same place.  */
+      if (__builtin_isnanf (f))
+	return runtime_fastrand1 ();
+
       return (uintptr_t) uf.si;
     }
   else if (key_size == 8)
@@ -45,8 +51,12 @@ 
 
       __builtin_memcpy (ud.a, vkey, 8);
       d = ud.d;
-      if (__builtin_isinf (d) || __builtin_isnan (d) || d == 0)
+      if (__builtin_isinf (d) || d == 0)
 	return 0;
+
+      if (__builtin_isnan (d))
+	return runtime_fastrand1 ();
+
       return (uintptr_t) ud.di;
     }
   else