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 81c28c4fe8
commit 9a78cb5d5f
4 changed files with 30 additions and 83 deletions

View File

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

View File

@ -250,6 +250,9 @@ struct JSThreadData {
/* 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;
@ -456,14 +459,6 @@ struct JSRuntime {
*/
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;

View File

@ -427,90 +427,47 @@ math_pow(JSContext *cx, uintN argc, jsval *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.
*/
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);
}
@ -716,13 +673,9 @@ math_pow_tn(jsdouble d, jsdouble 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
@ -752,7 +705,7 @@ JS_DEFINE_TRCINFO_1(math_min,
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,

View File

@ -51,10 +51,7 @@ 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