mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 07:05:24 +00:00
Use thread-local RNG for Math.random() (511328, r=shaver,waldo).
This commit is contained in:
parent
0c97581323
commit
b4232322c2
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user