Use thread-local RNG for Math.random() (511328, r=shaver,waldo).

This commit is contained in:
Andreas Gal 2009-08-19 15:23:54 -07:00
parent 0c97581323
commit b4232322c2
4 changed files with 30 additions and 83 deletions

View File

@ -58,6 +58,7 @@
#include "jsfun.h" #include "jsfun.h"
#include "jsgc.h" #include "jsgc.h"
#include "jslock.h" #include "jslock.h"
#include "jsmath.h"
#include "jsnum.h" #include "jsnum.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsopcode.h" #include "jsopcode.h"
@ -83,6 +84,7 @@ InitThreadData(JSThreadData *data)
#ifdef JS_TRACER #ifdef JS_TRACER
js_InitJIT(&data->traceMonitor); js_InitJIT(&data->traceMonitor);
#endif #endif
js_InitRandom(data);
} }
static void static void

View File

@ -250,6 +250,9 @@ struct JSThreadData {
/* Property cache for faster call/get/set invocation. */ /* Property cache for faster call/get/set invocation. */
JSPropertyCache propertyCache; JSPropertyCache propertyCache;
/* Random number generator state, used by jsmath.cpp. */
int64 rngSeed;
#ifdef JS_TRACER #ifdef JS_TRACER
/* Trace-tree JIT recorder/interpreter state. */ /* Trace-tree JIT recorder/interpreter state. */
JSTraceMonitor traceMonitor; JSTraceMonitor traceMonitor;
@ -456,14 +459,6 @@ struct JSRuntime {
*/ */
JSSetSlotRequest *setSlotRequests; 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. */ /* Well-known numbers held for use by this runtime's contexts. */
jsdouble *jsNaN; jsdouble *jsNaN;
jsdouble *jsNegativeInfinity; jsdouble *jsNegativeInfinity;

View File

@ -427,90 +427,47 @@ math_pow(JSContext *cx, uintN argc, jsval *vp)
return js_NewNumberInRootedValue(cx, z, vp); 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. * Math.random() support, lifted from java.util.Random.java.
*/ */
static void static inline void
random_setSeed(JSRuntime *rt, int64 seed) random_setSeed(JSThreadData *data, int64 seed)
{ {
int64 tmp; data->rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
JSLL_I2L(tmp, 1000);
JSLL_DIV(seed, seed, tmp);
JSLL_XOR(tmp, seed, rt->rngMultiplier);
JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
} }
void 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. */ /* Finally, set the seed from current time. */
random_setSeed(rt, PRMJ_Now()); random_setSeed(data, PRMJ_Now() / 1000);
} }
static uint32 static inline uint64
random_next(JSRuntime *rt, int bits) random_next(JSThreadData *data, int bits)
{ {
int64 nextseed, tmp; uint64 nextseed = data->rngSeed * RNG_MULTIPLIER;
uint32 retval; nextseed += RNG_ADDEND;
nextseed &= RNG_MASK;
JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier); data->rngSeed = nextseed;
JSLL_ADD(nextseed, nextseed, rt->rngAddend); return nextseed >> (48 - bits);
JSLL_AND(nextseed, nextseed, rt->rngMask);
rt->rngSeed = nextseed;
JSLL_USHR(tmp, nextseed, 48 - bits);
JSLL_L2I(retval, tmp);
return retval;
} }
jsdouble static inline jsdouble
js_random_nextDouble(JSRuntime *rt) random_nextDouble(JSThreadData *data)
{ {
int64 tmp, tmp2; return jsdouble((random_next(data, 26) << 27) + random_next(data, 27)) / RNG_DSCALE;
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;
} }
static JSBool static JSBool
math_random(JSContext *cx, uintN argc, jsval *vp) math_random(JSContext *cx, uintN argc, jsval *vp)
{ {
JSRuntime *rt; jsdouble z = random_nextDouble(JS_THREAD_DATA(cx));
jsdouble z;
rt = cx->runtime;
JS_LOCK_RUNTIME(rt);
js_random_init(rt);
z = js_random_nextDouble(rt);
JS_UNLOCK_RUNTIME(rt);
return js_NewNumberInRootedValue(cx, z, vp); return js_NewNumberInRootedValue(cx, z, vp);
} }
@ -716,13 +673,9 @@ math_pow_tn(jsdouble d, jsdouble p)
} }
static jsdouble FASTCALL static jsdouble FASTCALL
math_random_tn(JSRuntime* rt) math_random_tn(JSContext *cx)
{ {
JS_LOCK_RUNTIME(rt); return random_nextDouble(JS_THREAD_DATA(cx));
js_random_init(rt);
jsdouble z = js_random_nextDouble(rt);
JS_UNLOCK_RUNTIME(rt);
return z;
} }
static jsdouble FASTCALL static jsdouble FASTCALL
@ -752,7 +705,7 @@ JS_DEFINE_TRCINFO_1(math_min,
JS_DEFINE_TRCINFO_1(math_pow, JS_DEFINE_TRCINFO_1(math_pow,
(2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE, 1, 1))) (2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE, 1, 1)))
JS_DEFINE_TRCINFO_1(math_random, 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, JS_DEFINE_TRCINFO_1(math_round,
(1, (static, DOUBLE, math_round_tn, DOUBLE, 1, 1))) (1, (static, DOUBLE, math_round_tn, DOUBLE, 1, 1)))
JS_DEFINE_TRCINFO_1(math_ceil, JS_DEFINE_TRCINFO_1(math_ceil,

View File

@ -51,10 +51,7 @@ extern JSObject *
js_InitMathClass(JSContext *cx, JSObject *obj); js_InitMathClass(JSContext *cx, JSObject *obj);
extern void extern void
js_random_init(JSRuntime *rt); js_InitRandom(JSThreadData *data);
extern jsdouble
js_random_nextDouble(JSRuntime *rt);
JS_END_EXTERN_C JS_END_EXTERN_C