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/assembler.h"
9 #include "src/base/utils/random-number-generator.h"
10 #include "src/bootstrapper.h"
11 #include "src/codegen.h"
12
13 namespace v8 {
14 namespace internal {
15
RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers)16 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) {
17 HandleScope scope(isolate);
18 DCHECK(args.length() == 0);
19
20 Handle<Context> native_context = isolate->native_context();
21 DCHECK_EQ(0, native_context->math_random_index()->value());
22
23 static const int kCacheSize = 64;
24 static const int kState0Offset = kCacheSize - 1;
25 static const int kState1Offset = kState0Offset - 1;
26 // The index is decremented before used to access the cache.
27 static const int kInitialIndex = kState1Offset;
28
29 Handle<FixedDoubleArray> cache;
30 uint64_t state0 = 0;
31 uint64_t state1 = 0;
32 if (native_context->math_random_cache()->IsFixedDoubleArray()) {
33 cache = Handle<FixedDoubleArray>(
34 FixedDoubleArray::cast(native_context->math_random_cache()), isolate);
35 state0 = double_to_uint64(cache->get_scalar(kState0Offset));
36 state1 = double_to_uint64(cache->get_scalar(kState1Offset));
37 } else {
38 cache = Handle<FixedDoubleArray>::cast(
39 isolate->factory()->NewFixedDoubleArray(kCacheSize, TENURED));
40 native_context->set_math_random_cache(*cache);
41 // Initialize state if not yet initialized.
42 while (state0 == 0 || state1 == 0) {
43 isolate->random_number_generator()->NextBytes(&state0, sizeof(state0));
44 isolate->random_number_generator()->NextBytes(&state1, sizeof(state1));
45 }
46 }
47
48 DisallowHeapAllocation no_gc;
49 FixedDoubleArray* raw_cache = *cache;
50 // Create random numbers.
51 for (int i = 0; i < kInitialIndex; i++) {
52 // Generate random numbers using xorshift128+.
53 base::RandomNumberGenerator::XorShift128(&state0, &state1);
54 raw_cache->set(i, base::RandomNumberGenerator::ToDouble(state0, state1));
55 }
56
57 // Persist current state.
58 raw_cache->set(kState0Offset, uint64_to_double(state0));
59 raw_cache->set(kState1Offset, uint64_to_double(state1));
60 return Smi::FromInt(kInitialIndex);
61 }
62 } // namespace internal
63 } // namespace v8
64