From 8f6ac4ea64d3f05e7f8b7acb8cd0a0822c9c9e46 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 1 Apr 2025 12:33:17 +0200 Subject: [PATCH] LibJS: Use xorshift128++ PRNG for Math.random() This is the same PRNG used by major browser engines, and although it's a step down in randomness, it massively improves performance of Math.random(). 1.20x speedup on JetStream3/sync-file-system.js :^) --- Libraries/LibJS/Runtime/MathObject.cpp | 45 ++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/Libraries/LibJS/Runtime/MathObject.cpp b/Libraries/LibJS/Runtime/MathObject.cpp index 715b49655b3..0f6841c3d02 100644 --- a/Libraries/LibJS/Runtime/MathObject.cpp +++ b/Libraries/LibJS/Runtime/MathObject.cpp @@ -793,14 +793,55 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::pow) return pow_impl(vm, vm.argument(0), vm.argument(1)); } +class XorShift128PlusPlusRNG { +public: + XorShift128PlusPlusRNG() + { + u64 seed = get_random(); + m_low = splitmix64(seed); + m_high = splitmix64(seed); + } + + double get() + { + u64 value = advance() & ((1ULL << 53) - 1); + return value * (1.0 / (1ULL << 53)); + } + +private: + u64 splitmix64(u64& state) + { + u64 z = (state += 0x9e3779b97f4a7c15ULL); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL; + z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL; + return z ^ (z >> 31); + } + + u64 advance() + { + u64 s1 = m_low; + u64 const s0 = m_high; + u64 const result = s0 + s1; + m_low = s0; + s1 ^= s1 << 23; + s1 ^= s1 >> 17; + s1 ^= s0 ^ (s0 >> 26); + m_high = s1; + return result + s1; + } + + u64 m_low { 0 }; + u64 m_high { 0 }; +}; + // 21.3.2.27 Math.random ( ), https://tc39.es/ecma262/#sec-math.random JS_DEFINE_NATIVE_FUNCTION(MathObject::random) { // This function returns a Number value with positive sign, greater than or equal to +0𝔽 but strictly less than 1𝔽, // chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an // implementation-defined algorithm or strategy. - double r = (double)get_random() / (double)UINT32_MAX; - return Value(r); + static XorShift128PlusPlusRNG rng; + return rng.get(); } // 21.3.2.28 Math.round ( x ), https://tc39.es/ecma262/#sec-math.round