Revert "Issue #2895 - Replace XorShift128+ with Xoroshiro128++"

This reverts commit 1ba1395ca3.
non-64bit portion seems causing huge memory allocation and OOM later.
This commit is contained in:
2026-01-17 23:02:38 +08:00
parent aa5eeba9b2
commit 37c42449b4
24 changed files with 217 additions and 391 deletions
+40 -53
View File
@@ -12260,84 +12260,71 @@ CodeGenerator::visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins)
void
CodeGenerator::visitRandom(LRandom* ins)
{
using mozilla::non_crypto::Xoroshiro128PlusPlusRNG;
using mozilla::non_crypto::XorShift128PlusRNG;
FloatRegister output = ToFloatRegister(ins->output());
Register tempReg = ToRegister(ins->temp0());
#ifdef JS_PUNBOX64
Register64 s0Reg(ToRegister(ins->temp1()));
Register64 s1Reg(ToRegister(ins->temp2()));
// Helper registers for intermediate and final results
Register64 imr1Reg(ToRegister(ins->temp3()));
Register64 imr2Reg(ToRegister(ins->temp4()));
Register64 resultReg(ToRegister(ins->temp5()));
#else
Register64 s0Reg(ToRegister(ins->temp1()), ToRegister(ins->temp2()));
Register64 s1Reg(ToRegister(ins->temp3()), ToRegister(ins->temp4()));
// Helper registers for intermediate and final results
Register64 imr1Reg(ToRegister(ins->temp5()), ToRegister(ins->temp6()));
Register64 imr2Reg(ToRegister(ins->temp7()), ToRegister(ins->temp8()));
Register64 resultReg(ToRegister(ins->temp9()), ToRegister(ins->temp10()));
#endif
const void* rng = gen->compartment->addressOfRandomNumberGenerator();
masm.movePtr(ImmPtr(rng), tempReg);
static_assert(sizeof(Xoroshiro128PlusPlusRNG) == 2 * sizeof(uint64_t),
"Code below assumes Xoroshiro128PlusPlusRNG contains two uint64_t values");
static_assert(sizeof(XorShift128PlusRNG) == 2 * sizeof(uint64_t),
"Code below assumes XorShift128PlusRNG contains two uint64_t values");
Address state0Addr(tempReg, Xoroshiro128PlusPlusRNG::offsetOfState0());
Address state1Addr(tempReg, Xoroshiro128PlusPlusRNG::offsetOfState1());
Address state0Addr(tempReg, XorShift128PlusRNG::offsetOfState0());
Address state1Addr(tempReg, XorShift128PlusRNG::offsetOfState1());
// const uint64_t s0 = mState[0];
masm.load64(state0Addr, s0Reg);
// uint64_t s1 = mState[1];
masm.load64(state1Addr, s1Reg);
// const uint64_t result = rotl(s0 + s1, 17) + s0;
masm.move64(s0Reg, imr1Reg);
masm.add64(s1Reg, imr1Reg);
#ifdef JS_PUNBOX64
masm.rotateLeft64(Imm32(17), imr1Reg, resultReg);
#else
masm.rotateLeft64(Imm32(17), imr1Reg, resultReg, tempReg);
#endif
masm.add64(s0Reg, resultReg);
// s1 ^= s0;
// uint64_t s1 = mState[0];
masm.load64(state0Addr, s1Reg);
// s1 ^= s1 << 23;
masm.move64(s1Reg, s0Reg);
masm.lshift64(Imm32(23), s1Reg);
masm.xor64(s0Reg, s1Reg);
// mState[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b
#ifdef JS_PUNBOX64
masm.rotateLeft64(Imm32(49), s0Reg, imr1Reg); // imr = s0 rotl 49
#else
masm.rotateLeft64(Imm32(49), s0Reg, imr1Reg, tempReg); // imr = s0 rotl 49
#endif
masm.xor64(s1Reg, imr1Reg); // imr ^ s1
masm.move64(s1Reg, imr2Reg); // imr2 = s1
masm.lshift64(Imm32(21), imr2Reg); // imr2 << 21
masm.xor64(imr2Reg, imr1Reg); // imr ^ imr2
masm.store64(imr1Reg, state0Addr);
// mState[1] = rotl(s1, 28); // c
#ifdef JS_PUNBOX64
masm.rotateLeft64(Imm32(28), s1Reg, imr1Reg);
#else
masm.rotateLeft64(Imm32(28), s1Reg, imr1Reg, tempReg);
#endif
masm.store64(imr1Reg, state1Addr);
// s1 ^= s1 >> 17
masm.move64(s1Reg, s0Reg);
masm.rshift64(Imm32(17), s1Reg);
masm.xor64(s0Reg, s1Reg);
// See comment in Xoroshiro128PlusPlusRNG::nextDouble().
// const uint64_t s0 = mState[1];
masm.load64(state1Addr, s0Reg);
// mState[0] = s0;
masm.store64(s0Reg, state0Addr);
// s1 ^= s0
masm.xor64(s0Reg, s1Reg);
// s1 ^= s0 >> 26
masm.rshift64(Imm32(26), s0Reg);
masm.xor64(s0Reg, s1Reg);
// mState[1] = s1
masm.store64(s1Reg, state1Addr);
// s1 += mState[0]
masm.load64(state0Addr, s0Reg);
masm.add64(s0Reg, s1Reg);
// See comment in XorShift128PlusRNG::nextDouble().
static const int MantissaBits = FloatingPoint<double>::kExponentShift + 1;
static const double ScaleInv = double(1) / (1ULL << MantissaBits);
// Mask the result bits to mantissa size
masm.and64(Imm64((1ULL << MantissaBits) - 1), resultReg);
masm.and64(Imm64((1ULL << MantissaBits) - 1), s1Reg);
if (masm.convertUInt64ToDoubleNeedsTemp())
masm.convertUInt64ToDouble(resultReg, output, tempReg);
masm.convertUInt64ToDouble(s1Reg, output, tempReg);
else
masm.convertUInt64ToDouble(resultReg, output, Register::Invalid());
masm.convertUInt64ToDouble(s1Reg, output, Register::Invalid());
// output *= ScaleInv
masm.mulDoublePtr(ImmPtr(&ScaleInv), tempReg, output);
+13 -14
View File
@@ -1,7 +1,6 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2008 Apple Inc.
* Copyright (C) 2026 Moonchild Productions.
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -12,24 +11,24 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL APPLE INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef jit_ExecutableAllocator_h
#define jit_ExecutableAllocator_h
#include "mozilla/Maybe.h"
#include "mozilla/Xoroshiro128PlusPlusRNG.h"
#include "mozilla/XorShift128PlusRNG.h"
#include <limits>
#include <stddef.h> // for ptrdiff_t
+3 -3
View File
@@ -10,7 +10,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Maybe.h"
#include "mozilla/TaggedAnonymousMemory.h"
#include "mozilla/Xoroshiro128PlusPlusRNG.h"
#include "mozilla/XorShift128PlusRNG.h"
#include "jsfriendapi.h"
#include "jsmath.h"
@@ -441,7 +441,7 @@ class ProcessExecutableMemory
// Page where we should try to allocate next.
size_t cursor_;
mozilla::Maybe<mozilla::non_crypto::Xoroshiro128PlusPlusRNG> rng_;
mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> rng_;
PageBitSet<MaxCodePages> pages_;
public:
@@ -467,7 +467,7 @@ class ProcessExecutableMemory
base_ = static_cast<uint8_t*>(p);
mozilla::Array<uint64_t, 2> seed;
GenerateXoroshiro128PlusPlusSeed(seed);
GenerateXorShift128PlusSeed(seed);
rng_.emplace(seed[0], seed[1]);
return true;
}
-6
View File
@@ -978,12 +978,6 @@ void
LIRGeneratorARM::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
-3
View File
@@ -326,9 +326,6 @@ void
LIRGeneratorARM64::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp());
defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
-6
View File
@@ -249,12 +249,6 @@ void
LIRGeneratorMIPS::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
+1 -6
View File
@@ -178,11 +178,6 @@ LIRGeneratorMIPS64::lowerTruncateFToInt32(MTruncateToInt32* ins)
void
LIRGeneratorMIPS64::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp());
LRandom *lir = new(alloc()) LRandom(temp(), temp(), temp());
defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
}
+9 -36
View File
@@ -8244,9 +8244,9 @@ class LArrowNewTarget : public LInstructionHelper<BOX_PIECES, 1, 0>
// Math.random().
#ifdef JS_PUNBOX64
# define LRANDOM_NUM_TEMPS 6
# define LRANDOM_NUM_TEMPS 3
#else
# define LRANDOM_NUM_TEMPS 11
# define LRANDOM_NUM_TEMPS 5
#endif
class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
@@ -8254,27 +8254,18 @@ class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
public:
LIR_HEADER(Random)
LRandom(const LDefinition &temp0, const LDefinition &temp1,
const LDefinition &temp2, const LDefinition &temp3,
const LDefinition &temp4, const LDefinition &temp5
const LDefinition &temp2
#ifndef JS_PUNBOX64
, const LDefinition &temp6, const LDefinition &temp7
, const LDefinition &temp8, const LDefinition &temp9
, const LDefinition &temp10
, const LDefinition &temp3, const LDefinition &temp4
#endif
)
{
setTemp(0, temp0);
setTemp(1, temp1);
setTemp(2, temp2);
#ifndef JS_PUNBOX64
setTemp(3, temp3);
setTemp(4, temp4);
setTemp(5, temp5);
#ifndef JS_PUNBOX64
setTemp(6, temp6);
setTemp(7, temp7);
setTemp(8, temp8);
setTemp(9, temp9);
setTemp(10, temp10);
#endif
}
const LDefinition* temp0() {
@@ -8283,34 +8274,16 @@ class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
const LDefinition* temp1() {
return getTemp(1);
}
const LDefinition* temp2() {
const LDefinition *temp2() {
return getTemp(2);
}
const LDefinition* temp3() {
#ifndef JS_PUNBOX64
const LDefinition *temp3() {
return getTemp(3);
}
const LDefinition* temp4() {
const LDefinition *temp4() {
return getTemp(4);
}
const LDefinition* temp5() {
return getTemp(5);
}
#ifndef JS_PUNBOX64
const LDefinition* temp6() {
return getTemp(6);
}
const LDefinition* temp7() {
return getTemp(7);
}
const LDefinition* temp8() {
return getTemp(8);
}
const LDefinition* temp9() {
return getTemp(9);
}
const LDefinition* temp10() {
return getTemp(10);
}
#endif
MRandom* mir() const {
-3
View File
@@ -412,9 +412,6 @@ void
LIRGeneratorX64::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp());
defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
+4
View File
@@ -412,6 +412,7 @@ MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
void
MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
rolq_cl(dest.reg);
@@ -427,6 +428,7 @@ MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Re
void
MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
rorq_cl(dest.reg);
@@ -442,6 +444,7 @@ MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, R
void
MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
rolq(count, dest.reg);
}
@@ -455,6 +458,7 @@ MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Regis
void
MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
rorq(count, dest.reg);
}
-6
View File
@@ -607,12 +607,6 @@ void
LIRGeneratorX86::visitRandom(MRandom* ins)
{
LRandom *lir = new(alloc()) LRandom(temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
temp(),
+6
View File
@@ -497,6 +497,7 @@ MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
void
MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Register temp)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
Label done;
@@ -515,6 +516,7 @@ MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Re
void
MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, Register temp)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
Label done;
@@ -533,6 +535,8 @@ MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, R
void
MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Register temp)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
int32_t amount = count.value & 0x3f;
if ((amount & 0x1f) != 0) {
movl(dest.high, temp);
@@ -547,6 +551,8 @@ MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Regis
void
MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, Register temp)
{
MOZ_ASSERT(src == dest, "defineReuseInput");
int32_t amount = count.value & 0x3f;
if ((amount & 0x1f) != 0) {
movl(dest.high, temp);
+3 -3
View File
@@ -11,7 +11,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/Tuple.h"
#include "mozilla/Variant.h"
#include "mozilla/Xoroshiro128PlusPlusRNG.h"
#include "mozilla/XorShift128PlusRNG.h"
#include "builtin/RegExp.h"
#include "gc/Barrier.h"
@@ -696,13 +696,13 @@ struct JSCompartment
js::DtoaCache dtoaCache;
// Random number generator for Math.random().
mozilla::Maybe<mozilla::non_crypto::Xoroshiro128PlusPlusRNG> randomNumberGenerator;
mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
// Initialize randomNumberGenerator if needed.
void ensureRandomNumberGenerator();
private:
mozilla::non_crypto::Xoroshiro128PlusPlusRNG randomKeyGenerator_;
mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_;
public:
js::HashNumber randomHashCode();
+3 -3
View File
@@ -737,9 +737,9 @@ js::GenerateRandomSeed()
}
void
js::GenerateXoroshiro128PlusPlusSeed(mozilla::Array<uint64_t, 2>& seed)
js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed)
{
// Xoroshiro128PlusPlusRNG must be initialized with a non-zero seed.
// XorShift128PlusRNG must be initialized with a non-zero seed.
do {
seed[0] = GenerateRandomSeed();
seed[1] = GenerateRandomSeed();
@@ -751,7 +751,7 @@ JSCompartment::ensureRandomNumberGenerator()
{
if (randomNumberGenerator.isNothing()) {
mozilla::Array<uint64_t, 2> seed;
GenerateXoroshiro128PlusPlusSeed(seed);
GenerateXorShift128PlusSeed(seed);
randomNumberGenerator.emplace(seed[0], seed[1]);
}
}
+2 -2
View File
@@ -89,9 +89,9 @@ extern uint64_t
GenerateRandomSeed();
// Fill |seed[0]| and |seed[1]| with random bits, suitable for
// seeding a Xoroshiro128++ random number generator.
// seeding a XorShift128+ random number generator.
extern void
GenerateXoroshiro128PlusPlusSeed(mozilla::Array<uint64_t, 2>& seed);
GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
extern uint64_t
random_next(uint64_t* rngState, int bits);
@@ -1,110 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Math.random() uniformity and speed test using canvas</title>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<form>
<input type="radio" id="original" name="color" value="original" checked />
<label for="original">Original</label>
<input type="radio" id="grayscale" name="color" value="grayscale" />
<label for="grayscale">Grayscale</label>
<input type="radio" id="inverted" name="color" value="inverted" />
<label for="inverted">Inverted</label>
<input type="radio" id="sepia" name="color" value="sepia" />
<label for="sepia">Sepia</label>
<div id="timing"></div>
</form>
<script>
const c = document.getElementById("canvas");
const ctx = c.getContext("2d");
const duration = document.getElementById("timing");
const original = () => {
var startTime = performance.now();
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.random()*255; // red
data[i + 1] = Math.random()*255; // green
data[i + 2] = Math.random()*255; // blue
data[i+3] = 255;
}
ctx.putImageData(imageData, 0, 0);
var endTime = performance.now();
duration.innerHTML = "Total pixels: " + (data.length / 4) +" -- Time taken: " + (endTime - startTime) + " ms";
};
const invert = () => {
var startTime = performance.now();
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // red
data[i + 1] = 255 - data[i + 1]; // green
data[i + 2] = 255 - data[i + 2]; // blue
}
ctx.putImageData(imageData, 0, 0);
var endTime = performance.now();
duration.innerHTML = "Total pixels: " + (data.length / 4) +" -- Time taken: " + (endTime - startTime) + " ms";
};
const grayscale = () => {
var startTime = performance.now();
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const avg = Math.random()*255;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
data[i+3] = 255;
}
ctx.putImageData(imageData, 0, 0);
var endTime = performance.now();
duration.innerHTML = "Total pixels: " + (data.length / 4) +" -- Time taken: " + (endTime - startTime) + " ms";
};
const sepia = () => {
var startTime = performance.now();
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
let r = data[i], // red
g = data[i + 1], // green
b = data[i + 2]; // blue
data[i] = Math.min(Math.round(0.393 * r + 0.769 * g + 0.189 * b), 255);
data[i + 1] = Math.min(Math.round(0.349 * r + 0.686 * g + 0.168 * b), 255);
data[i + 2] = Math.min(Math.round(0.272 * r + 0.534 * g + 0.131 * b), 255);
}
ctx.putImageData(imageData, 0, 0);
var endTime = performance.now();
duration.innerHTML = "Total pixels: " + (data.length / 4) +" -- Time taken: " + (endTime - startTime) + " ms";
};
const inputs = document.querySelectorAll("[name=color]");
for (const input of inputs) {
input.addEventListener("change", (evt) => {
switch (evt.target.value) {
case "inverted":
return invert();
case "grayscale":
return grayscale();
case "sepia":
return sepia();
default:
return original();
}
});
}
</script>
</body>
</html>
+4 -4
View File
@@ -781,13 +781,13 @@ JSRuntime::removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promis
PromiseRejectionHandlingState::Handled, data);
}
mozilla::non_crypto::Xoroshiro128PlusPlusRNG&
mozilla::non_crypto::XorShift128PlusRNG&
JSRuntime::randomKeyGenerator()
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
if (randomKeyGenerator_.isNothing()) {
mozilla::Array<uint64_t, 2> seed;
GenerateXoroshiro128PlusPlusSeed(seed);
GenerateXorShift128PlusSeed(seed);
randomKeyGenerator_.emplace(seed[0], seed[1]);
}
return randomKeyGenerator_.ref();
@@ -800,11 +800,11 @@ JSRuntime::randomHashCodeScrambler()
return mozilla::HashCodeScrambler(rng.next(), rng.next());
}
mozilla::non_crypto::Xoroshiro128PlusPlusRNG
mozilla::non_crypto::XorShift128PlusRNG
JSRuntime::forkRandomKeyGenerator()
{
auto& rng = randomKeyGenerator();
return mozilla::non_crypto::Xoroshiro128PlusPlusRNG(rng.next(), rng.next());
return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
}
void
+3 -3
View File
@@ -778,12 +778,12 @@ struct JSRuntime : public JS::shadow::Runtime,
private:
// Used to generate random keys for hash tables.
mozilla::Maybe<mozilla::non_crypto::Xoroshiro128PlusPlusRNG> randomKeyGenerator_;
mozilla::non_crypto::Xoroshiro128PlusPlusRNG& randomKeyGenerator();
mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_;
mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator();
public:
mozilla::HashCodeScrambler randomHashCodeScrambler();
mozilla::non_crypto::Xoroshiro128PlusPlusRNG forkRandomKeyGenerator();
mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator();
//-------------------------------------------------------------------------
// Self-hosting support
+1 -1
View File
@@ -1595,7 +1595,7 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
if (!bernoulliSeeded) {
mozilla::Array<uint64_t, 2> seed;
GenerateXoroshiro128PlusPlusSeed(seed);
GenerateXorShift128PlusSeed(seed);
bernoulli.setRandomState(seed[0], seed[1]);
bernoulliSeeded = true;
}
+1 -1
View File
@@ -177,7 +177,7 @@ class SavedStacks {
// Set the sampling random number generator's state to |state0| and
// |state1|. One or the other must be non-zero. See the comments for
// mozilla::non_crypto::Xoroshiro128PlusPlusRNG::setState for details.
// mozilla::non_crypto::XorShift128PlusRNG::setState for details.
void setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+2 -2
View File
@@ -8,7 +8,7 @@
#define mozilla_FastBernoulliTrial_h
#include "mozilla/Assertions.h"
#include "mozilla/Xoroshiro128PlusPlusRNG.h"
#include "mozilla/XorShift128PlusRNG.h"
#include <cmath>
#include <stdint.h>
@@ -304,7 +304,7 @@ class FastBernoulliTrial {
double mInvLogNotProbability;
/* Our random number generator. */
non_crypto::Xoroshiro128PlusPlusRNG mGenerator;
non_crypto::XorShift128PlusRNG mGenerator;
/* The number of times |trial| should return false before next returning true. */
size_t mSkipCount;
+121
View File
@@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* The xorshift128+ pseudo-random number generator. */
#ifndef mozilla_XorShift128Plus_h
#define mozilla_XorShift128Plus_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include <inttypes.h>
namespace mozilla {
namespace non_crypto {
/*
* A stream of pseudo-random numbers generated using the xorshift+ technique
* described here:
*
* Vigna, Sebastiano (2014). "Further scramblings of Marsaglia's xorshift
* generators". arXiv:1404.0390 (http://arxiv.org/abs/1404.0390)
*
* That paper says:
*
* In particular, we propose a tightly coded xorshift128+ generator that
* does not fail systematically any test from the BigCrush suite of TestU01
* (even reversed) and generates 64 pseudorandom bits in 1.10 ns on an
* Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest
* generator we are aware of with such empirical statistical properties.
*
* The stream of numbers produced by this method repeats every 2**128 - 1 calls
* (i.e. never, for all practical purposes). Zero appears 2**64 - 1 times in
* this period; all other numbers appear 2**64 times. Additionally, each *bit*
* in the produced numbers repeats every 2**128 - 1 calls.
*
* This generator is not suitable as a cryptographically secure random number
* generator.
*/
class XorShift128PlusRNG {
uint64_t mState[2];
public:
/*
* Construct a xorshift128+ pseudo-random number stream using |aInitial0| and
* |aInitial1| as the initial state. These MUST NOT both be zero.
*
* If the initial states contain many zeros, for a few iterations you'll see
* many zeroes in the generated numbers. It's suggested to seed a SplitMix64
* generator <http://xorshift.di.unimi.it/splitmix64.c> and use its first two
* outputs to seed xorshift128+.
*/
XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) {
setState(aInitial0, aInitial1);
}
/**
* Return a pseudo-random 64-bit number.
*/
uint64_t next() {
/*
* The offsetOfState*() methods below are provided so that exceedingly-rare
* callers that want to observe or poke at RNG state in C++ type-system-
* ignoring means can do so. Don't change the next() or nextDouble()
* algorithms without altering code that uses offsetOfState*()!
*/
uint64_t s1 = mState[0];
const uint64_t s0 = mState[1];
mState[0] = s0;
s1 ^= s1 << 23;
mState[1] = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26);
return mState[1] + s0;
}
/*
* Return a pseudo-random floating-point value in the range [0, 1). More
* precisely, choose an integer in the range [0, 2**53) and divide it by
* 2**53. Given the 2**128 - 1 period noted above, the produced doubles are
* all but uniformly distributed in this range.
*/
double nextDouble() {
/*
* Because the IEEE 64-bit floating point format stores the leading '1' bit
* of the mantissa implicitly, it effectively represents a mantissa in the
* range [0, 2**53) in only 52 bits. FloatingPoint<double>::kExponentShift
* is the width of the bitfield in the in-memory format, so we must add one
* to get the mantissa's range.
*/
static constexpr int kMantissaBits =
mozilla::FloatingPoint<double>::kExponentShift + 1;
uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1);
return double(mantissa) / (UINT64_C(1) << kMantissaBits);
}
/*
* Set the stream's current state to |aState0| and |aState1|. These must not
* both be zero; ideally, they should have an almost even mix of zero and one
* bits.
*/
void setState(uint64_t aState0, uint64_t aState1) {
MOZ_ASSERT(aState0 || aState1);
mState[0] = aState0;
mState[1] = aState1;
}
static size_t offsetOfState0() {
return offsetof(XorShift128PlusRNG, mState[0]);
}
static size_t offsetOfState1() {
return offsetof(XorShift128PlusRNG, mState[1]);
}
};
} // namespace non_crypto
} // namespace mozilla
#endif // mozilla_XorShift128Plus_h
-125
View File
@@ -1,125 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* The xoroshiro128++ pseudo-random number generator. */
#ifndef mozilla_Xoroshiro128PlusPlus_h
#define mozilla_Xoroshiro128PlusPlus_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include <inttypes.h>
namespace mozilla {
namespace non_crypto {
/*
* A stream of pseudo-random numbers generated using the xoroshiro128++ technique described here:
*
* Blackman, David and Vigna, Sebastiano (2019). "A PRNG Shootout"
* https://prng.di.unimi.it/
*
* That paper says:
*
* xoshiro256++/xoshiro256** (XOR/shift/rotate) are our all-purpose generators (not cryptographically secure
* generators, though, like all PRNGs in these pages). They have excellent (sub-ns) speed, a state space
* (256 bits) that is large enough for any parallel application, and they pass all tests we are aware of.
* If you are tight on space, xoroshiro128++/xoroshiro128** (XOR/rotate/shift/rotate) and xoroshiro128+ have
* the same speed and use half of the space; the same comments apply.
* They are suitable only for low-scale parallel applications.
*
* The stream of numbers produced by this method repeats every 2**256 - 1 calls (i.e. never, for all practical
* purposes).
*
*/
class Xoroshiro128PlusPlusRNG {
uint64_t mState[2];
public:
/*
* Construct a xoroshiro128++ pseudo-random number stream using |aInitial0| and |aInitial1| as the initial state.
* These MUST NOT both be zero.
*
* If the initial states contain many zeros, for a few iterations you'll see many zeroes in the generated numbers.
* It's suggested to seed a SplitMix64 generator <http://xorshift.di.unimi.it/splitmix64.c> and use its first two
* outputs to seed xoroshiro128++.
*/
Xoroshiro128PlusPlusRNG(uint64_t aInitial0, uint64_t aInitial1) {
setState(aInitial0, aInitial1);
}
/**
* Helper function:
* Rotate a 64-bit number left by a specified number of positions
*/
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
/**
* Return a pseudo-random 64-bit number.
*/
uint64_t next() {
/*
* The offsetOfState*() methods below are provided so that exceedingly-rare callers (like our JIT...) that want to
* observe or poke at RNG state in C++ type-system-ignoring means can do so. Don't change the next() or nextDouble()
* algorithms without altering code that uses offsetOfState*()!
*/
const uint64_t s0 = mState[0];
uint64_t s1 = mState[1];
const uint64_t result = rotl(s0 + s1, 17) + s0;
s1 ^= s0;
mState[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b
mState[1] = rotl(s1, 28); // c
return result;
}
/*
* Return a pseudo-random floating-point value in the range [0, 1). More
* precisely, choose an integer in the range [0, 2**53) and divide it by
* 2**53. Given the 2**256 - 1 period noted above, the produced doubles are
* all but uniformly distributed in this range.
*/
double nextDouble() {
/*
* Because the IEEE 64-bit floating point format stores the leading '1' bit
* of the mantissa implicitly, it effectively represents a mantissa in the
* range [0, 2**53) in only 52 bits. FloatingPoint<double>::kExponentShift
* is the width of the bitfield in the in-memory format, so we must add one
* to get the mantissa's range.
*/
static constexpr int kMantissaBits =
mozilla::FloatingPoint<double>::kExponentShift + 1;
uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1);
return double(mantissa) / (UINT64_C(1) << kMantissaBits);
}
/*
* Set the stream's current state to |aState0| and |aState1|. These must not
* both be zero; ideally, they should have an almost even mix of zero and one
* bits.
*/
void setState(uint64_t aState0, uint64_t aState1) {
MOZ_ASSERT(aState0 || aState1);
mState[0] = aState0;
mState[1] = aState1;
}
static size_t offsetOfState0() {
return offsetof(Xoroshiro128PlusPlusRNG, mState[0]);
}
static size_t offsetOfState1() {
return offsetof(Xoroshiro128PlusPlusRNG, mState[1]);
}
};
} // namespace non_crypto
} // namespace mozilla
#endif // mozilla_Xoroshiro128PlusPlus_h
+1 -1
View File
@@ -103,7 +103,7 @@ EXPORTS.mozilla = [
'Vector.h',
'WeakPtr.h',
'WrappingOperations.h',
'Xoroshiro128PlusPlusRNG.h',
'XorShift128PlusRNG.h',
]
if CONFIG['OS_ARCH'] == 'WINNT':