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/math-random.h"
6
7#include "src/assert-scope.h"
8#include "src/base/utils/random-number-generator.h"
9#include "src/contexts-inl.h"
10#include "src/isolate.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 =
20 Handle<FixedDoubleArray>::cast(isolate->factory()->NewFixedDoubleArray(
21 kCacheSize, AllocationType::kOld));
22 for (int i = 0; i < kCacheSize; i++) cache->set(i, 0);
23 native_context->set_math_random_cache(*cache);
24 Handle<PodArray<State>> pod =
25 PodArray<State>::New(isolate, 1, AllocationType::kOld);
26 native_context->set_math_random_state(*pod);
27 ResetContext(*native_context);
28}
29
30void MathRandom::ResetContext(Context native_context) {
31 native_context->set_math_random_index(Smi::zero());
32 State state = {0, 0};
33 PodArray<State>::cast(native_context->math_random_state())->set(0, state);
34}
35
36Address MathRandom::RefillCache(Isolate* isolate, Address raw_native_context) {
37 Context native_context = Context::cast(Object(raw_native_context));
38 DisallowHeapAllocation no_gc;
39 PodArray<State> pod =
40 PodArray<State>::cast(native_context->math_random_state());
41 State state = pod->get(0);
42 // Initialize state if not yet initialized. If a fixed random seed was
43 // requested, use it to reset our state the first time a script asks for
44 // random numbers in this context. This ensures the script sees a consistent
45 // sequence.
46 if (state.s0 == 0 && state.s1 == 0) {
47 uint64_t seed;
48 if (FLAG_random_seed != 0) {
49 seed = FLAG_random_seed;
50 } else {
51 isolate->random_number_generator()->NextBytes(&seed, sizeof(seed));
52 }
53 state.s0 = base::RandomNumberGenerator::MurmurHash3(seed);
54 state.s1 = base::RandomNumberGenerator::MurmurHash3(~seed);
55 CHECK(state.s0 != 0 || state.s1 != 0);
56 }
57
58 FixedDoubleArray cache =
59 FixedDoubleArray::cast(native_context->math_random_cache());
60 // Create random numbers.
61 for (int i = 0; i < kCacheSize; i++) {
62 // Generate random numbers using xorshift128+.
63 base::RandomNumberGenerator::XorShift128(&state.s0, &state.s1);
64 cache->set(i, base::RandomNumberGenerator::ToDouble(state.s0));
65 }
66 pod->set(0, state);
67
68 Smi new_index = Smi::FromInt(kCacheSize);
69 native_context->set_math_random_index(new_index);
70 return new_index.ptr();
71}
72
73} // namespace internal
74} // namespace v8
75