• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace v8 {
15 namespace internal {
16 
InitializeContext(Isolate * isolate,Handle<Context> native_context)17 void 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 
ResetContext(Context native_context)29 void 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 
RefillCache(Isolate * isolate,Address raw_native_context)35 Address 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