• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/runtime/runtime-utils.h"
6 
7 #include "src/arguments.h"
8 #include "src/base/utils/random-number-generator.h"
9 #include "src/bootstrapper.h"
10 #include "src/counters.h"
11 #include "src/double.h"
12 #include "src/objects-inl.h"
13 
14 namespace v8 {
15 namespace internal {
16 
RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers)17 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) {
18   HandleScope scope(isolate);
19   DCHECK_EQ(0, args.length());
20 
21   Handle<Context> native_context = isolate->native_context();
22   DCHECK_EQ(0, native_context->math_random_index()->value());
23 
24   static const int kCacheSize = 64;
25   static const int kState0Offset = kCacheSize - 1;
26   static const int kState1Offset = kState0Offset - 1;
27   // The index is decremented before used to access the cache.
28   static const int kInitialIndex = kState1Offset;
29 
30   Handle<FixedDoubleArray> cache;
31   uint64_t state0 = 0;
32   uint64_t state1 = 0;
33   if (native_context->math_random_cache()->IsFixedDoubleArray()) {
34     cache = Handle<FixedDoubleArray>(
35         FixedDoubleArray::cast(native_context->math_random_cache()), isolate);
36     state0 = double_to_uint64(cache->get_scalar(kState0Offset));
37     state1 = double_to_uint64(cache->get_scalar(kState1Offset));
38   } else {
39     cache = Handle<FixedDoubleArray>::cast(
40         isolate->factory()->NewFixedDoubleArray(kCacheSize, TENURED));
41     native_context->set_math_random_cache(*cache);
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 (FLAG_random_seed != 0) {
47       state0 = FLAG_random_seed;
48       state1 = FLAG_random_seed;
49     } else {
50       while (state0 == 0 || state1 == 0) {
51         isolate->random_number_generator()->NextBytes(&state0, sizeof(state0));
52         isolate->random_number_generator()->NextBytes(&state1, sizeof(state1));
53       }
54     }
55   }
56 
57   DisallowHeapAllocation no_gc;
58   FixedDoubleArray* raw_cache = *cache;
59   // Create random numbers.
60   for (int i = 0; i < kInitialIndex; i++) {
61     // Generate random numbers using xorshift128+.
62     base::RandomNumberGenerator::XorShift128(&state0, &state1);
63     raw_cache->set(i, base::RandomNumberGenerator::ToDouble(state0, state1));
64   }
65 
66   // Persist current state.
67   raw_cache->set(kState0Offset, uint64_to_double(state0));
68   raw_cache->set(kState1Offset, uint64_to_double(state1));
69   return Smi::FromInt(kInitialIndex);
70 }
71 }  // namespace internal
72 }  // namespace v8
73