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 16 RUNTIME_FUNCTION(Runtime_DoubleHi) { 17 HandleScope scope(isolate); 18 DCHECK(args.length() == 1); 19 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 20 uint64_t unsigned64 = double_to_uint64(x); 21 uint32_t unsigned32 = static_cast<uint32_t>(unsigned64 >> 32); 22 int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32); 23 return *isolate->factory()->NewNumber(signed32); 24 } 25 26 27 RUNTIME_FUNCTION(Runtime_DoubleLo) { 28 HandleScope scope(isolate); 29 DCHECK(args.length() == 1); 30 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 31 uint64_t unsigned64 = double_to_uint64(x); 32 uint32_t unsigned32 = static_cast<uint32_t>(unsigned64); 33 int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32); 34 return *isolate->factory()->NewNumber(signed32); 35 } 36 37 38 // Slow version of Math.pow. We check for fast paths for special cases. 39 // Used if VFP3 is not available. 40 RUNTIME_FUNCTION(Runtime_MathPow) { 41 HandleScope scope(isolate); 42 DCHECK(args.length() == 2); 43 isolate->counters()->math_pow_runtime()->Increment(); 44 45 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 46 47 // If the second argument is a smi, it is much faster to call the 48 // custom powi() function than the generic pow(). 49 if (args[1]->IsSmi()) { 50 int y = args.smi_at(1); 51 return *isolate->factory()->NewNumber(power_double_int(x, y)); 52 } 53 54 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 55 double result = power_helper(isolate, x, y); 56 if (std::isnan(result)) return isolate->heap()->nan_value(); 57 return *isolate->factory()->NewNumber(result); 58 } 59 60 61 // Fast version of Math.pow if we know that y is not an integer and y is not 62 // -0.5 or 0.5. Used as slow case from full codegen. 63 RUNTIME_FUNCTION(Runtime_MathPowRT) { 64 HandleScope scope(isolate); 65 DCHECK(args.length() == 2); 66 isolate->counters()->math_pow_runtime()->Increment(); 67 68 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 69 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 70 if (y == 0) { 71 return Smi::FromInt(1); 72 } else { 73 double result = power_double_double(x, y); 74 if (std::isnan(result)) return isolate->heap()->nan_value(); 75 return *isolate->factory()->NewNumber(result); 76 } 77 } 78 79 80 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) { 81 HandleScope scope(isolate); 82 DCHECK(args.length() == 1); 83 if (isolate->serializer_enabled()) { 84 // Random numbers in the snapshot are not really that random. And we cannot 85 // return a typed array as it cannot be serialized. To make calling 86 // Math.random possible when creating a custom startup snapshot, we simply 87 // return a normal array with a single random number. 88 Handle<HeapNumber> random_number = isolate->factory()->NewHeapNumber( 89 isolate->random_number_generator()->NextDouble()); 90 Handle<FixedArray> array_backing = isolate->factory()->NewFixedArray(1); 91 array_backing->set(0, *random_number); 92 return *isolate->factory()->NewJSArrayWithElements(array_backing); 93 } 94 95 static const int kState0Offset = 0; 96 static const int kState1Offset = 1; 97 static const int kRandomBatchSize = 64; 98 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_typed_array, 0); 99 Handle<JSTypedArray> typed_array; 100 // Allocate typed array if it does not yet exist. 101 if (maybe_typed_array->IsJSTypedArray()) { 102 typed_array = Handle<JSTypedArray>::cast(maybe_typed_array); 103 } else { 104 static const int kByteLength = kRandomBatchSize * kDoubleSize; 105 Handle<JSArrayBuffer> buffer = 106 isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED); 107 JSArrayBuffer::SetupAllocatingData(buffer, isolate, kByteLength, true, 108 SharedFlag::kNotShared); 109 typed_array = isolate->factory()->NewJSTypedArray( 110 kExternalFloat64Array, buffer, 0, kRandomBatchSize); 111 } 112 113 DisallowHeapAllocation no_gc; 114 double* array = 115 reinterpret_cast<double*>(typed_array->GetBuffer()->backing_store()); 116 // Fetch existing state. 117 uint64_t state0 = double_to_uint64(array[kState0Offset]); 118 uint64_t state1 = double_to_uint64(array[kState1Offset]); 119 // Initialize state if not yet initialized. 120 while (state0 == 0 || state1 == 0) { 121 isolate->random_number_generator()->NextBytes(&state0, sizeof(state0)); 122 isolate->random_number_generator()->NextBytes(&state1, sizeof(state1)); 123 } 124 // Create random numbers. 125 for (int i = kState1Offset + 1; i < kRandomBatchSize; i++) { 126 // Generate random numbers using xorshift128+. 127 base::RandomNumberGenerator::XorShift128(&state0, &state1); 128 array[i] = base::RandomNumberGenerator::ToDouble(state0, state1); 129 } 130 // Persist current state. 131 array[kState0Offset] = uint64_to_double(state0); 132 array[kState1Offset] = uint64_to_double(state1); 133 return *typed_array; 134 } 135 } // namespace internal 136 } // namespace v8 137