Patchwork libgo patch committed: Return random number of hash of NaN

login
register
mail settings
Submitter Ian Taylor
Date Sept. 22, 2012, 6:06 a.m.
Message ID <mcrpq5eoakg.fsf@google.com>
Download mbox | patch
Permalink /patch/186096/
State New
Headers show

Comments

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

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