[JAEGER] Minor merge from TM to pick up a small perf boost and see if we can cycle TBPL into actually working again
authorDavid Mandelin <dmandelin@mozilla.com>
Thu, 19 Aug 2010 16:05:06 -0700
changeset 53461 dfd2e154a6a5dea2dae7ab6eff66b2e32c603caa
parent 53460 79ef58bbf0e897cbff440b5045b6e23643fe73e1 (current diff)
parent 51119 5c0d9233b34f217d12ef45aaed299b1d31c46548 (diff)
child 53463 b0fa07efbce2cc488adf62335bb5c28e0f378d0a
push idunknown
push userunknown
push dateunknown
milestone2.0b5pre
[JAEGER] Minor merge from TM to pick up a small perf boost and see if we can cycle TBPL into actually working again
js/src/jsmath.cpp
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -393,43 +393,90 @@ js_math_min(JSContext *cx, uintN argc, V
         } else {
             z = (x < z) ? x : z;
         }
     }
     vp->setNumber(z);
     return JS_TRUE;
 }
 
+static jsdouble
+powi(jsdouble x, jsint y)
+{
+    jsuint n = (y < 0) ? -y : y;
+    jsdouble m = x;
+    jsdouble p = 1;
+    while (true) {
+        if ((n & 1) != 0) p *= m;
+        n >>= 1;
+        if (n == 0) {
+            if (y < 0) {
+                // Unfortunately, we have to be careful when p has reached
+                // infinity in the computation, because sometimes the higher
+                // internal precision in the pow() implementation would have
+                // given us a finite p. This happens very rarely.
+                
+                jsdouble result = 1.0 / p;
+                return (result == 0 && JSDOUBLE_IS_INFINITE(p))
+                       ? pow(x, static_cast<jsdouble>(y))  // Avoid pow(double, int).
+                       : result;
+            }
+
+            return p;
+        }
+        m *= m;
+    }
+}
+
 static JSBool
 math_pow(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, y, z;
 
     if (argc <= 1) {
         vp->setDouble(js_NaN);
         return JS_TRUE;
     }
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     if (!ValueToNumber(cx, vp[3], &y))
         return JS_FALSE;
     /*
+     * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
+     * when x = -0.0, so we have to guard for this.
+     */
+    if (JSDOUBLE_IS_FINITE(x) && x != 0.0) {
+        if (y == 0.5) {
+            vp->setNumber(sqrt(x));
+            return JS_TRUE;
+        }
+        if (y == -0.5) {
+            vp->setNumber(1.0/sqrt(x));
+            return JS_TRUE;
+        }
+    }
+    /*
      * Because C99 and ECMA specify different behavior for pow(),
      * we need to wrap the libm call to make it ECMA compliant.
      */
     if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
         vp->setDouble(js_NaN);
         return JS_TRUE;
     }
     /* pow(x, +-0) is always 1, even for x = NaN. */
     if (y == 0) {
         vp->setInt32(1);
         return JS_TRUE;
     }
-    z = pow(x, y);
+
+    if (vp[3].isInt32())
+        z = powi(x, vp[3].toInt32());
+    else
+        z = pow(x, y);
+
     vp->setNumber(z);
     return JS_TRUE;
 }
 
 static const int64 RNG_MULTIPLIER = 0x5DEECE66DLL;
 static const int64 RNG_ADDEND = 0xBLL;
 static const int64 RNG_MASK = (1LL << 48) - 1;
 static const jsdouble RNG_DSCALE = jsdouble(1LL << 53);
@@ -668,20 +715,35 @@ math_min_tn(jsdouble d, jsdouble p)
         return d;
     }
     return (p < d) ? p : d;
 }
 
 static jsdouble FASTCALL
 math_pow_tn(jsdouble d, jsdouble p)
 {
+    /*
+     * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
+     * when x = -0.0, so we have to guard for this.
+     */
+    if (JSDOUBLE_IS_FINITE(d) && d != 0.0) {
+        if (p == 0.5)
+            return sqrt(d);
+
+        if (p == -0.5)
+            return 1.0/sqrt(d);
+    }
     if (!JSDOUBLE_IS_FINITE(p) && (d == 1.0 || d == -1.0))
         return js_NaN;
     if (p == 0)
         return 1.0;
+    int32_t i;
+    if (JSDOUBLE_IS_INT32(p, &i))
+        return powi(d, i);
+
     return pow(d, p);
 }
 
 static jsdouble FASTCALL
 math_random_tn(JSContext *cx)
 {
     return random_nextDouble(cx);
 }