1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/numbers/math-random.h" 6 7#include "src/base/utils/random-number-generator.h" 8#include "src/common/assert-scope.h" 9#include "src/execution/isolate.h" 10#include "src/objects/contexts-inl.h" 11#include "src/objects/fixed-array.h" 12#include "src/objects/smi.h" 13 14namespace v8 { 15namespace internal { 16 17void MathRandom::InitializeContext(Isolate* isolate, 18 Handle<Context> native_context) { 19 Handle<FixedDoubleArray> cache = Handle<FixedDoubleArray>::cast( 20 isolate->factory()->NewFixedDoubleArray(kCacheSize)); 21 for (int i = 0; i < kCacheSize; i++) cache->set(i, 0); 22 native_context->set_math_random_cache(*cache); 23 Handle<PodArray<State>> pod = 24 PodArray<State>::New(isolate, 1, AllocationType::kOld); 25 native_context->set_math_random_state(*pod); 26 ResetContext(*native_context); 27} 28 29void MathRandom::ResetContext(Context native_context) { 30 native_context.set_math_random_index(Smi::zero()); 31 State state = {0, 0}; 32 PodArray<State>::cast(native_context.math_random_state()).set(0, state); 33} 34 35Address MathRandom::RefillCache(Isolate* isolate, Address raw_native_context) { 36 Context native_context = Context::cast(Object(raw_native_context)); 37 DisallowGarbageCollection no_gc; 38 PodArray<State> pod = 39 PodArray<State>::cast(native_context.math_random_state()); 40 State state = pod.get(0); 41 // Initialize state if not yet initialized. If a fixed random seed was 42 // requested, use it to reset our state the first time a script asks for 43 // random numbers in this context. This ensures the script sees a consistent 44 // sequence. 45 if (state.s0 == 0 && state.s1 == 0) { 46 uint64_t seed; 47 if (FLAG_random_seed != 0) { 48 seed = FLAG_random_seed; 49 } else { 50 isolate->random_number_generator()->NextBytes(&seed, sizeof(seed)); 51 } 52 state.s0 = base::RandomNumberGenerator::MurmurHash3(seed); 53 state.s1 = base::RandomNumberGenerator::MurmurHash3(~seed); 54 CHECK(state.s0 != 0 || state.s1 != 0); 55 } 56 57 FixedDoubleArray cache = 58 FixedDoubleArray::cast(native_context.math_random_cache()); 59 // Create random numbers. 60 for (int i = 0; i < kCacheSize; i++) { 61 // Generate random numbers using xorshift128+. 62 base::RandomNumberGenerator::XorShift128(&state.s0, &state.s1); 63 cache.set(i, base::RandomNumberGenerator::ToDouble(state.s0)); 64 } 65 pod.set(0, state); 66 67 Smi new_index = Smi::FromInt(kCacheSize); 68 native_context.set_math_random_index(new_index); 69 return new_index.ptr(); 70} 71 72} // namespace internal 73} // namespace v8 74