mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -978,12 +978,6 @@ void
|
||||
LIRGeneratorARM::visitRandom(MRandom* ins)
|
||||
{
|
||||
LRandom *lir = new(alloc()) LRandom(temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -249,12 +249,6 @@ void
|
||||
LIRGeneratorMIPS::visitRandom(MRandom* ins)
|
||||
{
|
||||
LRandom *lir = new(alloc()) LRandom(temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -607,12 +607,6 @@ void
|
||||
LIRGeneratorX86::visitRandom(MRandom* ins)
|
||||
{
|
||||
LRandom *lir = new(alloc()) LRandom(temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
temp(),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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>
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -103,7 +103,7 @@ EXPORTS.mozilla = [
|
||||
'Vector.h',
|
||||
'WeakPtr.h',
|
||||
'WrappingOperations.h',
|
||||
'Xoroshiro128PlusPlusRNG.h',
|
||||
'XorShift128PlusRNG.h',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
||||
Reference in New Issue
Block a user