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