[JAEGER] Minor merge from TM to pick up a small perf boost and see if we can cycle TBPL into actually working again
 author David Mandelin Thu, 19 Aug 2010 16:05:06 -0700 changeset 53461 dfd2e154a6a5dea2dae7ab6eff66b2e32c603caa parent 53460 79ef58bbf0e897cbff440b5045b6e23643fe73e1 (current diff) parent 51119 5c0d9233b34f217d12ef45aaed299b1d31c46548 (diff) child 53463 b0fa07efbce2cc488adf62335bb5c28e0f378d0a push id unknown push user unknown push date unknown milestone 2.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 file | annotate | diff | comparison | revisions
--- 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);
}