Commit 33fa357b authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

Do not use FixedDoubleArray to store RNG state

Also:
 - replace runtime call with cheaper C call
 - use xor instead of addition to remove bias

R=mvstanton@chromium.org

Bug: v8:8212
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: If4bfe0f5fb1864c89f4acd871cb8b74c7cd7ab09
Reviewed-on: https://chromium-review.googlesource.com/1240116
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56165}
parent 071d3c66
......@@ -2164,6 +2164,8 @@ v8_source_set("v8_base") {
"src/macro-assembler.h",
"src/map-updater.cc",
"src/map-updater.h",
"src/math-random.cc",
"src/math-random.h",
"src/maybe-handles-inl.h",
"src/maybe-handles.h",
"src/messages.cc",
......@@ -2404,7 +2406,6 @@ v8_source_set("v8_base") {
"src/runtime/runtime-interpreter.cc",
"src/runtime/runtime-intl.cc",
"src/runtime/runtime-literals.cc",
"src/runtime/runtime-maths.cc",
"src/runtime/runtime-module.cc",
"src/runtime/runtime-numbers.cc",
"src/runtime/runtime-object.cc",
......
......@@ -99,7 +99,7 @@ int RandomNumberGenerator::NextInt(int max) {
double RandomNumberGenerator::NextDouble() {
XorShift128(&state0_, &state1_);
return ToDouble(state0_, state1_);
return ToDouble(state0_);
}
......
......@@ -108,11 +108,10 @@ class V8_BASE_EXPORT RandomNumberGenerator final {
int64_t initial_seed() const { return initial_seed_; }
// Static and exposed for external use.
static inline double ToDouble(uint64_t state0, uint64_t state1) {
static inline double ToDouble(uint64_t state0) {
// Exponent for double values for [1.0 .. 2.0)
static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000};
static const uint64_t kMantissaMask = uint64_t{0x000FFFFFFFFFFFFF};
uint64_t random = ((state0 + state1) & kMantissaMask) | kExponentBits;
uint64_t random = (state0 >> 12) | kExponentBits;
return bit_cast<double>(random) - 1;
}
......
......@@ -19,6 +19,7 @@
#include "src/extensions/trigger-failure-extension.h"
#include "src/heap/heap.h"
#include "src/isolate-inl.h"
#include "src/math-random.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/arguments.h"
#include "src/objects/hash-table-inl.h"
......@@ -5769,6 +5770,7 @@ Genesis::Genesis(
DCHECK_EQ(0u, context_snapshot_index);
// We get here if there was no context snapshot.
CreateRoots();
MathRandom::InitializeContext(isolate, native_context());
Handle<JSFunction> empty_function = CreateEmptyFunction();
CreateSloppyModeFunctionMaps(empty_function);
CreateStrictModeFunctionMaps(empty_function);
......
......@@ -413,7 +413,16 @@ TF_BUILTIN(MathRandom, CodeStubAssembler) {
GotoIf(SmiAbove(smi_index.value(), SmiConstant(0)), &if_cached);
// Cache exhausted, populate the cache. Return value is the new index.
smi_index = CAST(CallRuntime(Runtime::kGenerateRandomNumbers, context));
Node* const refill_math_random =
ExternalConstant(ExternalReference::refill_math_random());
Node* const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_tagged = MachineType::AnyTagged();
MachineType type_ptr = MachineType::Pointer();
smi_index =
CAST(CallCFunction2(type_tagged, type_ptr, type_tagged,
refill_math_random, isolate_ptr, native_context));
Goto(&if_cached);
// Compute next index by decrement.
......
......@@ -233,7 +233,8 @@ enum ContextLookupFlags {
V(MAP_KEY_VALUE_ITERATOR_MAP_INDEX, Map, map_key_value_iterator_map) \
V(MAP_VALUE_ITERATOR_MAP_INDEX, Map, map_value_iterator_map) \
V(MATH_RANDOM_INDEX_INDEX, Smi, math_random_index) \
V(MATH_RANDOM_CACHE_INDEX, Object, math_random_cache) \
V(MATH_RANDOM_STATE_INDEX, ByteArray, math_random_state) \
V(MATH_RANDOM_CACHE_INDEX, FixedDoubleArray, math_random_cache) \
V(MESSAGE_LISTENERS_INDEX, TemplateList, message_listeners) \
V(NATIVES_UTILS_OBJECT_INDEX, Object, natives_utils_object) \
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
......
......@@ -308,7 +308,6 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(ArrayIndexOf) \
V(ArrayIsArray) \
V(ClassOf) \
V(GenerateRandomNumbers) \
V(GetFunctionName) \
V(GetOwnPropertyDescriptor) \
V(GlobalPrint) \
......
......@@ -16,6 +16,7 @@
#include "src/ic/stub-cache.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate.h"
#include "src/math-random.h"
#include "src/objects-inl.h"
#include "src/regexp/regexp-stack.h"
#include "src/simulator-base.h"
......@@ -719,6 +720,10 @@ ExternalReference ExternalReference::printf_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(std::printf)));
}
ExternalReference ExternalReference::refill_math_random() {
return ExternalReference(Redirect(FUNCTION_ADDR(MathRandom::RefillCache)));
}
template <typename SubjectChar, typename PatternChar>
ExternalReference ExternalReference::search_string_raw() {
auto f = SearchStringRaw<SubjectChar, PatternChar>;
......
......@@ -133,6 +133,7 @@ class StatsCounter;
V(orderedhashmap_gethash_raw, "orderedhashmap_gethash_raw") \
V(power_double_double_function, "power_double_double_function") \
V(printf_function, "printf") \
V(refill_math_random, "MathRandom::RefillCache") \
V(store_buffer_overflow_function, "StoreBuffer::StoreBufferOverflow") \
V(search_string_raw_one_one, "search_string_raw_one_one") \
V(search_string_raw_one_two, "search_string_raw_one_two") \
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/math-random.h"
#include "src/assert-scope.h"
#include "src/base/utils/random-number-generator.h"
#include "src/contexts-inl.h"
#include "src/isolate.h"
#include "src/objects/fixed-array.h"
namespace v8 {
namespace internal {
void MathRandom::InitializeContext(Isolate* isolate,
Handle<Context> native_context) {
Handle<FixedDoubleArray> cache = Handle<FixedDoubleArray>::cast(
isolate->factory()->NewFixedDoubleArray(kCacheSize, TENURED));
native_context->set_math_random_cache(*cache);
Handle<PodArray<State>> pod = PodArray<State>::New(isolate, 1, TENURED);
native_context->set_math_random_state(*pod);
ResetContext(*native_context);
}
void MathRandom::ResetContext(Context* native_context) {
native_context->set_math_random_index(Smi::kZero);
State state = {0, 0};
PodArray<State>::cast(native_context->math_random_state())->set(0, state);
}
Smi* MathRandom::RefillCache(Isolate* isolate, Context* native_context) {
DisallowHeapAllocation no_gc;
PodArray<State>* pod =
PodArray<State>::cast(native_context->math_random_state());
State state = pod->get(0);
// Initialize state if not yet initialized. If a fixed random seed was
// requested, use it to reset our state the first time a script asks for
// random numbers in this context. This ensures the script sees a consistent
// sequence.
if (state.s0 == 0 || state.s1 == 0) {
if (FLAG_random_seed != 0) {
state.s0 = FLAG_random_seed;
state.s1 = FLAG_random_seed;
} else {
base::RandomNumberGenerator* rng = isolate->random_number_generator();
while (state.s0 == 0 || state.s1 == 0) {
rng->NextBytes(&state.s0, sizeof(state.s0));
rng->NextBytes(&state.s1, sizeof(state.s1));
}
}
}
FixedDoubleArray* cache =
FixedDoubleArray::cast(native_context->math_random_cache());
// Create random numbers.
for (int i = 0; i < kCacheSize; i++) {
// Generate random numbers using xorshift128+.
base::RandomNumberGenerator::XorShift128(&state.s0, &state.s1);
cache->set(i, base::RandomNumberGenerator::ToDouble(state.s0));
}
pod->set(0, state);
Smi* new_index = Smi::FromInt(kCacheSize);
native_context->set_math_random_index(new_index);
return new_index;
}
} // namespace internal
} // namespace v8
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_MATH_RANDOM_H_
#define V8_MATH_RANDOM_H_
#include "src/contexts.h"
#include "src/globals.h"
namespace v8 {
namespace internal {
class MathRandom : public AllStatic {
public:
static void InitializeContext(Isolate* isolate,
Handle<Context> native_context);
static void ResetContext(Context* native_context);
static Smi* RefillCache(Isolate* isolate, Context* native_context);
static const int kCacheSize = 64;
static const int kStateSize = 2 * kInt64Size;
struct State {
uint64_t s0;
uint64_t s1;
};
};
} // namespace internal
} // namespace v8
#endif // V8_MATH_RANDOM_H_
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/base/utils/random-number-generator.h"
#include "src/bootstrapper.h"
#include "src/counters.h"
#include "src/double.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
Handle<Context> native_context = isolate->native_context();
DCHECK_EQ(0, native_context->math_random_index()->value());
static const int kCacheSize = 64;
static const int kState0Offset = kCacheSize - 1;
static const int kState1Offset = kState0Offset - 1;
// The index is decremented before used to access the cache.
static const int kInitialIndex = kState1Offset;
Handle<FixedDoubleArray> cache;
uint64_t state0 = 0;
uint64_t state1 = 0;
if (native_context->math_random_cache()->IsFixedDoubleArray()) {
cache = Handle<FixedDoubleArray>(
FixedDoubleArray::cast(native_context->math_random_cache()), isolate);
state0 = double_to_uint64(cache->get_scalar(kState0Offset));
state1 = double_to_uint64(cache->get_scalar(kState1Offset));
} else {
cache = Handle<FixedDoubleArray>::cast(
isolate->factory()->NewFixedDoubleArray(kCacheSize, TENURED));
native_context->set_math_random_cache(*cache);
// Initialize state if not yet initialized. If a fixed random seed was
// requested, use it to reset our state the first time a script asks for
// random numbers in this context. This ensures the script sees a consistent
// sequence.
if (FLAG_random_seed != 0) {
state0 = FLAG_random_seed;
state1 = FLAG_random_seed;
} else {
while (state0 == 0 || state1 == 0) {
isolate->random_number_generator()->NextBytes(&state0, sizeof(state0));
isolate->random_number_generator()->NextBytes(&state1, sizeof(state1));
}
}
}
DisallowHeapAllocation no_gc;
FixedDoubleArray* raw_cache = *cache;
// Create random numbers.
for (int i = 0; i < kInitialIndex; i++) {
// Generate random numbers using xorshift128+.
base::RandomNumberGenerator::XorShift128(&state0, &state1);
raw_cache->set(i, base::RandomNumberGenerator::ToDouble(state0, state1));
}
// Persist current state.
raw_cache->set(kState0Offset, uint64_to_double(state0));
raw_cache->set(kState1Offset, uint64_to_double(state1));
return Smi::FromInt(kInitialIndex);
}
} // namespace internal
} // namespace v8
......@@ -256,8 +256,6 @@ namespace internal {
F(CreateObjectLiteralWithoutAllocationSite, 2, 1) \
F(CreateRegExpLiteral, 4, 1)
#define FOR_EACH_INTRINSIC_MATHS(F) F(GenerateRandomNumbers, 0, 1)
#define FOR_EACH_INTRINSIC_MODULE(F) \
F(DynamicImportCall, 2, 1) \
F(GetImportMetaObject, 0, 1) \
......@@ -581,7 +579,6 @@ namespace internal {
FOR_EACH_INTRINSIC_INTERPRETER(F) \
FOR_EACH_INTRINSIC_INTL(F) \
FOR_EACH_INTRINSIC_LITERALS(F) \
FOR_EACH_INTRINSIC_MATHS(F) \
FOR_EACH_INTRINSIC_MODULE(F) \
FOR_EACH_INTRINSIC_NUMBERS(F) \
FOR_EACH_INTRINSIC_OBJECT(F) \
......
......@@ -6,6 +6,7 @@
#include "src/snapshot/startup-serializer.h"
#include "src/api-inl.h"
#include "src/math-random.h"
#include "src/objects-inl.h"
namespace v8 {
......@@ -40,8 +41,7 @@ void PartialSerializer::Serialize(Context** o, bool include_global_proxy) {
ReadOnlyRoots(isolate()).undefined_value());
DCHECK(!context_->global_object()->IsUndefined());
// Reset math random cache to get fresh random numbers.
context_->set_math_random_index(Smi::kZero);
context_->set_math_random_cache(ReadOnlyRoots(isolate()).undefined_value());
MathRandom::ResetContext(context_);
VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
reinterpret_cast<Object**>(o));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment