Use thread-local RNG for Math.random() (511328, r=shaver,waldo).
authorAndreas Gal <gal@mozilla.com>
Wed, 19 Aug 2009 15:23:54 -0700
changeset 31898 0307226048c86a41ad74b8d8be2c75c93763bf7c
parent 31897 2e528cc8602a697b5c6fd63bdfe477ef8a997b7c
child 31899 85832269fb645d617b094fc98a26e1c0fca05c98
push id8746
push userrsayre@mozilla.com
push dateTue, 25 Aug 2009 16:53:43 +0000
treeherdermozilla-central@189759c41621 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshaver, waldo
bugs511328
milestone1.9.3a1pre
Use thread-local RNG for Math.random() (511328, r=shaver,waldo).
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsmath.cpp
js/src/jsmath.h
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -53,16 +53,17 @@
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jslock.h"
+#include "jsmath.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspubtd.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
@@ -78,16 +79,17 @@ InitThreadData(JSThreadData *data)
 #ifdef DEBUG
     /* The data must be already zeroed. */
     for (size_t i = 0; i != sizeof(*data); ++i)
         JS_ASSERT(reinterpret_cast<uint8*>(data)[i] == 0);
 #endif
 #ifdef JS_TRACER
     js_InitJIT(&data->traceMonitor);
 #endif
+    js_InitRandom(data);
 }
 
 static void
 FinishThreadData(JSThreadData *data)
 {
 #ifdef DEBUG
     /* All GC-related things must be already removed at this point. */
     for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -245,16 +245,19 @@ struct JSThreadData {
      * The GSN cache is per thread since even multi-cx-per-thread embeddings
      * do not interleave js_GetSrcNote calls.
      */
     JSGSNCache          gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
     JSPropertyCache     propertyCache;
 
+    /* Random number generator state, used by jsmath.cpp. */
+    int64               rngSeed;
+
 #ifdef JS_TRACER
     /* Trace-tree JIT recorder/interpreter state. */
     JSTraceMonitor      traceMonitor;
 #endif
 
     /* Lock-free hashed lists of scripts created by eval to garbage-collect. */
     JSScript            *scriptsToGC[JS_EVAL_CACHE_SIZE];
 
@@ -451,24 +454,16 @@ struct JSRuntime {
     /*
      * Used to serialize cycle checks when setting __proto__ or __parent__ by
      * requesting the GC handle the required cycle detection. If the GC hasn't
      * been poked, it won't scan for garbage. This member is protected by
      * rt->gcLock.
      */
     JSSetSlotRequest    *setSlotRequests;
 
-    /* Random number generator state, used by jsmath.c. */
-    JSBool              rngInitialized;
-    int64               rngMultiplier;
-    int64               rngAddend;
-    int64               rngMask;
-    int64               rngSeed;
-    jsdouble            rngDscale;
-
     /* Well-known numbers held for use by this runtime's contexts. */
     jsdouble            *jsNaN;
     jsdouble            *jsNegativeInfinity;
     jsdouble            *jsPositiveInfinity;
 
 #ifdef JS_THREADSAFE
     JSLock              *deflatedStringCacheLock;
 #endif
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -422,100 +422,57 @@ math_pow(JSContext *cx, uintN argc, jsva
     if (y == 0) {
         *vp = JSVAL_ONE;
         return JS_TRUE;
     }
     z = pow(x, y);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
+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);
+
 /*
  * Math.random() support, lifted from java.util.Random.java.
  */
-static void
-random_setSeed(JSRuntime *rt, int64 seed)
+static inline void
+random_setSeed(JSThreadData *data, int64 seed)
 {
-    int64 tmp;
-
-    JSLL_I2L(tmp, 1000);
-    JSLL_DIV(seed, seed, tmp);
-    JSLL_XOR(tmp, seed, rt->rngMultiplier);
-    JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
+    data->rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
 }
 
 void
-js_random_init(JSRuntime *rt)
+js_InitRandom(JSThreadData *data)
 {
-    int64 tmp, tmp2;
-
-    /* Do at most once. */
-    if (rt->rngInitialized)
-        return;
-    rt->rngInitialized = JS_TRUE;
-
-    /* rt->rngMultiplier = 0x5DEECE66DL */
-    JSLL_ISHL(tmp, 0x5, 32);
-    JSLL_UI2L(tmp2, 0xDEECE66DL);
-    JSLL_OR(rt->rngMultiplier, tmp, tmp2);
-
-    /* rt->rngAddend = 0xBL */
-    JSLL_I2L(rt->rngAddend, 0xBL);
-
-    /* rt->rngMask = (1L << 48) - 1 */
-    JSLL_I2L(tmp, 1);
-    JSLL_SHL(tmp2, tmp, 48);
-    JSLL_SUB(rt->rngMask, tmp2, tmp);
-
-    /* rt->rngDscale = (jsdouble)(1L << 53) */
-    JSLL_SHL(tmp2, tmp, 53);
-    JSLL_L2D(rt->rngDscale, tmp2);
-
     /* Finally, set the seed from current time. */
-    random_setSeed(rt, PRMJ_Now());
+    random_setSeed(data, PRMJ_Now() / 1000);
 }
 
-static uint32
-random_next(JSRuntime *rt, int bits)
+static inline uint64
+random_next(JSThreadData *data, int bits)
 {
-    int64 nextseed, tmp;
-    uint32 retval;
-
-    JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier);
-    JSLL_ADD(nextseed, nextseed, rt->rngAddend);
-    JSLL_AND(nextseed, nextseed, rt->rngMask);
-    rt->rngSeed = nextseed;
-    JSLL_USHR(tmp, nextseed, 48 - bits);
-    JSLL_L2I(retval, tmp);
-    return retval;
+    uint64 nextseed = data->rngSeed * RNG_MULTIPLIER;
+    nextseed += RNG_ADDEND;
+    nextseed &= RNG_MASK;
+    data->rngSeed = nextseed;
+    return nextseed >> (48 - bits);
 }
 
-jsdouble
-js_random_nextDouble(JSRuntime *rt)
+static inline jsdouble
+random_nextDouble(JSThreadData *data)
 {
-    int64 tmp, tmp2;
-    jsdouble d;
-
-    JSLL_ISHL(tmp, random_next(rt, 26), 27);
-    JSLL_UI2L(tmp2, random_next(rt, 27));
-    JSLL_ADD(tmp, tmp, tmp2);
-    JSLL_L2D(d, tmp);
-    return d / rt->rngDscale;
+    return jsdouble((random_next(data, 26) << 27) + random_next(data, 27)) / RNG_DSCALE;
 }
 
 static JSBool
 math_random(JSContext *cx, uintN argc, jsval *vp)
 {
-    JSRuntime *rt;
-    jsdouble z;
-
-    rt = cx->runtime;
-    JS_LOCK_RUNTIME(rt);
-    js_random_init(rt);
-    z = js_random_nextDouble(rt);
-    JS_UNLOCK_RUNTIME(rt);
+    jsdouble z = random_nextDouble(JS_THREAD_DATA(cx));
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 #if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
 /* Try to work around apparent _copysign bustage in VC6 and VC7. */
 double
 js_copysign(double x, double y)
 {
@@ -711,23 +668,19 @@ math_pow_tn(jsdouble d, jsdouble p)
     if (!JSDOUBLE_IS_FINITE(p) && (d == 1.0 || d == -1.0))
         return js_NaN;
     if (p == 0)
         return 1.0;
     return pow(d, p);
 }
 
 static jsdouble FASTCALL
-math_random_tn(JSRuntime* rt)
+math_random_tn(JSContext *cx)
 {
-    JS_LOCK_RUNTIME(rt);
-    js_random_init(rt);
-    jsdouble z = js_random_nextDouble(rt);
-    JS_UNLOCK_RUNTIME(rt);
-    return z;
+    return random_nextDouble(JS_THREAD_DATA(cx));
 }
 
 static jsdouble FASTCALL
 math_round_tn(jsdouble x)
 {
     return js_copysign(floor(x + 0.5), x);
 }
 
@@ -747,17 +700,17 @@ JS_DEFINE_TRCINFO_1(math_log,
     (1, (static, DOUBLE, math_log_tn, DOUBLE,           1, 1)))
 JS_DEFINE_TRCINFO_1(math_max,
     (2, (static, DOUBLE, math_max_tn, DOUBLE, DOUBLE,   1, 1)))
 JS_DEFINE_TRCINFO_1(math_min,
     (2, (static, DOUBLE, math_min_tn, DOUBLE, DOUBLE,   1, 1)))
 JS_DEFINE_TRCINFO_1(math_pow,
     (2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE,   1, 1)))
 JS_DEFINE_TRCINFO_1(math_random,
-    (1, (static, DOUBLE, math_random_tn, RUNTIME,       0, 0)))
+    (1, (static, DOUBLE, math_random_tn, CONTEXT,       0, 0)))
 JS_DEFINE_TRCINFO_1(math_round,
     (1, (static, DOUBLE, math_round_tn, DOUBLE,         1, 1)))
 JS_DEFINE_TRCINFO_1(math_ceil,
     (1, (static, DOUBLE, math_ceil_tn, DOUBLE,          1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec math_static_methods[] = {
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -46,16 +46,13 @@
 JS_BEGIN_EXTERN_C
 
 extern JSClass js_MathClass;
 
 extern JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj);
 
 extern void
-js_random_init(JSRuntime *rt);
-
-extern jsdouble
-js_random_nextDouble(JSRuntime *rt);
+js_InitRandom(JSThreadData *data);
 
 JS_END_EXTERN_C
 
 #endif /* jsmath_h___ */