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 | |
14 | namespace v8 { |
15 | namespace internal { |
16 | |
17 | void 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 | |
30 | void 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 | |
36 | Address 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 | |