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/third_party/fdlibm/fdlibm.h" 13 14 namespace v8 { 15 namespace internal { 16 17 #define RUNTIME_UNARY_MATH(Name, name) \ 18 RUNTIME_FUNCTION(Runtime_Math##Name) { \ 19 HandleScope scope(isolate); \ 20 DCHECK(args.length() == 1); \ 21 isolate->counters()->math_##name()->Increment(); \ 22 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \ 23 return *isolate->factory()->NewHeapNumber(std::name(x)); \ 24 } 25 26 RUNTIME_UNARY_MATH(Acos, acos) 27 RUNTIME_UNARY_MATH(Asin, asin) 28 RUNTIME_UNARY_MATH(Atan, atan) 29 RUNTIME_UNARY_MATH(LogRT, log) 30 #undef RUNTIME_UNARY_MATH 31 32 33 RUNTIME_FUNCTION(Runtime_DoubleHi) { 34 HandleScope scope(isolate); 35 DCHECK(args.length() == 1); 36 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 37 uint64_t unsigned64 = double_to_uint64(x); 38 uint32_t unsigned32 = static_cast<uint32_t>(unsigned64 >> 32); 39 int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32); 40 return *isolate->factory()->NewNumber(signed32); 41 } 42 43 44 RUNTIME_FUNCTION(Runtime_DoubleLo) { 45 HandleScope scope(isolate); 46 DCHECK(args.length() == 1); 47 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 48 uint64_t unsigned64 = double_to_uint64(x); 49 uint32_t unsigned32 = static_cast<uint32_t>(unsigned64); 50 int32_t signed32 = bit_cast<int32_t, uint32_t>(unsigned32); 51 return *isolate->factory()->NewNumber(signed32); 52 } 53 54 55 RUNTIME_FUNCTION(Runtime_ConstructDouble) { 56 HandleScope scope(isolate); 57 DCHECK(args.length() == 2); 58 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); 59 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); 60 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; 61 return *isolate->factory()->NewNumber(uint64_to_double(result)); 62 } 63 64 65 RUNTIME_FUNCTION(Runtime_RemPiO2) { 66 SealHandleScope shs(isolate); 67 DisallowHeapAllocation no_gc; 68 DCHECK(args.length() == 2); 69 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 70 CONVERT_ARG_CHECKED(JSTypedArray, result, 1); 71 RUNTIME_ASSERT(result->byte_length() == Smi::FromInt(2 * sizeof(double))); 72 FixedFloat64Array* array = FixedFloat64Array::cast(result->elements()); 73 double* y = static_cast<double*>(array->DataPtr()); 74 return Smi::FromInt(fdlibm::rempio2(x, y)); 75 } 76 77 78 static const double kPiDividedBy4 = 0.78539816339744830962; 79 80 81 RUNTIME_FUNCTION(Runtime_MathAtan2) { 82 HandleScope scope(isolate); 83 DCHECK(args.length() == 2); 84 isolate->counters()->math_atan2()->Increment(); 85 86 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 87 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 88 double result; 89 if (std::isinf(x) && std::isinf(y)) { 90 // Make sure that the result in case of two infinite arguments 91 // is a multiple of Pi / 4. The sign of the result is determined 92 // by the first argument (x) and the sign of the second argument 93 // determines the multiplier: one or three. 94 int multiplier = (x < 0) ? -1 : 1; 95 if (y < 0) multiplier *= 3; 96 result = multiplier * kPiDividedBy4; 97 } else { 98 result = std::atan2(x, y); 99 } 100 return *isolate->factory()->NewNumber(result); 101 } 102 103 104 RUNTIME_FUNCTION(Runtime_MathExpRT) { 105 HandleScope scope(isolate); 106 DCHECK(args.length() == 1); 107 isolate->counters()->math_exp()->Increment(); 108 109 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 110 lazily_initialize_fast_exp(isolate); 111 return *isolate->factory()->NewNumber(fast_exp(x, isolate)); 112 } 113 114 115 RUNTIME_FUNCTION(Runtime_MathClz32) { 116 HandleScope scope(isolate); 117 DCHECK(args.length() == 1); 118 isolate->counters()->math_clz32()->Increment(); 119 120 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 121 return *isolate->factory()->NewNumberFromUint( 122 base::bits::CountLeadingZeros32(x)); 123 } 124 125 126 RUNTIME_FUNCTION(Runtime_MathFloor) { 127 HandleScope scope(isolate); 128 DCHECK(args.length() == 1); 129 isolate->counters()->math_floor()->Increment(); 130 131 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 132 return *isolate->factory()->NewNumber(Floor(x)); 133 } 134 135 136 // Slow version of Math.pow. We check for fast paths for special cases. 137 // Used if VFP3 is not available. 138 RUNTIME_FUNCTION(Runtime_MathPow) { 139 HandleScope scope(isolate); 140 DCHECK(args.length() == 2); 141 isolate->counters()->math_pow()->Increment(); 142 143 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 144 145 // If the second argument is a smi, it is much faster to call the 146 // custom powi() function than the generic pow(). 147 if (args[1]->IsSmi()) { 148 int y = args.smi_at(1); 149 return *isolate->factory()->NewNumber(power_double_int(x, y)); 150 } 151 152 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 153 double result = power_helper(isolate, x, y); 154 if (std::isnan(result)) return isolate->heap()->nan_value(); 155 return *isolate->factory()->NewNumber(result); 156 } 157 158 159 // Fast version of Math.pow if we know that y is not an integer and y is not 160 // -0.5 or 0.5. Used as slow case from full codegen. 161 RUNTIME_FUNCTION(Runtime_MathPowRT) { 162 HandleScope scope(isolate); 163 DCHECK(args.length() == 2); 164 isolate->counters()->math_pow()->Increment(); 165 166 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 167 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 168 if (y == 0) { 169 return Smi::FromInt(1); 170 } else { 171 double result = power_double_double(x, y); 172 if (std::isnan(result)) return isolate->heap()->nan_value(); 173 return *isolate->factory()->NewNumber(result); 174 } 175 } 176 177 178 RUNTIME_FUNCTION(Runtime_RoundNumber) { 179 HandleScope scope(isolate); 180 DCHECK(args.length() == 1); 181 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); 182 isolate->counters()->math_round()->Increment(); 183 184 if (!input->IsHeapNumber()) { 185 DCHECK(input->IsSmi()); 186 return *input; 187 } 188 189 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input); 190 191 double value = number->value(); 192 int exponent = number->get_exponent(); 193 int sign = number->get_sign(); 194 195 if (exponent < -1) { 196 // Number in range ]-0.5..0.5[. These always round to +/-zero. 197 if (sign) return isolate->heap()->minus_zero_value(); 198 return Smi::FromInt(0); 199 } 200 201 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and 202 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar 203 // argument holds for 32-bit smis). 204 if (!sign && exponent < kSmiValueSize - 2) { 205 return Smi::FromInt(static_cast<int>(value + 0.5)); 206 } 207 208 // If the magnitude is big enough, there's no place for fraction part. If we 209 // try to add 0.5 to this number, 1.0 will be added instead. 210 if (exponent >= 52) { 211 return *number; 212 } 213 214 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); 215 216 // Do not call NumberFromDouble() to avoid extra checks. 217 return *isolate->factory()->NewNumber(Floor(value + 0.5)); 218 } 219 220 221 RUNTIME_FUNCTION(Runtime_MathSqrt) { 222 HandleScope scope(isolate); 223 DCHECK(args.length() == 1); 224 isolate->counters()->math_sqrt()->Increment(); 225 226 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 227 lazily_initialize_fast_sqrt(isolate); 228 return *isolate->factory()->NewNumber(fast_sqrt(x, isolate)); 229 } 230 231 232 RUNTIME_FUNCTION(Runtime_MathFround) { 233 HandleScope scope(isolate); 234 DCHECK(args.length() == 1); 235 236 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 237 float xf = DoubleToFloat32(x); 238 return *isolate->factory()->NewNumber(xf); 239 } 240 241 242 RUNTIME_FUNCTION(Runtime_IsMinusZero) { 243 SealHandleScope shs(isolate); 244 DCHECK(args.length() == 1); 245 CONVERT_ARG_CHECKED(Object, obj, 0); 246 if (!obj->IsHeapNumber()) return isolate->heap()->false_value(); 247 HeapNumber* number = HeapNumber::cast(obj); 248 return isolate->heap()->ToBoolean(IsMinusZero(number->value())); 249 } 250 251 252 RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers) { 253 HandleScope scope(isolate); 254 DCHECK(args.length() == 1); 255 // Random numbers in the snapshot are not really that random. 256 DCHECK(!isolate->bootstrapper()->IsActive()); 257 static const int kState0Offset = 0; 258 static const int kState1Offset = 1; 259 static const int kRandomBatchSize = 64; 260 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_typed_array, 0); 261 Handle<JSTypedArray> typed_array; 262 // Allocate typed array if it does not yet exist. 263 if (maybe_typed_array->IsJSTypedArray()) { 264 typed_array = Handle<JSTypedArray>::cast(maybe_typed_array); 265 } else { 266 static const int kByteLength = kRandomBatchSize * kDoubleSize; 267 Handle<JSArrayBuffer> buffer = 268 isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED); 269 JSArrayBuffer::SetupAllocatingData(buffer, isolate, kByteLength, true, 270 SharedFlag::kNotShared); 271 typed_array = isolate->factory()->NewJSTypedArray( 272 kExternalFloat64Array, buffer, 0, kRandomBatchSize); 273 } 274 275 DisallowHeapAllocation no_gc; 276 double* array = 277 reinterpret_cast<double*>(typed_array->GetBuffer()->backing_store()); 278 // Fetch existing state. 279 uint64_t state0 = double_to_uint64(array[kState0Offset]); 280 uint64_t state1 = double_to_uint64(array[kState1Offset]); 281 // Initialize state if not yet initialized. 282 while (state0 == 0 || state1 == 0) { 283 isolate->random_number_generator()->NextBytes(&state0, sizeof(state0)); 284 isolate->random_number_generator()->NextBytes(&state1, sizeof(state1)); 285 } 286 // Create random numbers. 287 for (int i = kState1Offset + 1; i < kRandomBatchSize; i++) { 288 // Generate random numbers using xorshift128+. 289 base::RandomNumberGenerator::XorShift128(&state0, &state1); 290 array[i] = base::RandomNumberGenerator::ToDouble(state0, state1); 291 } 292 // Persist current state. 293 array[kState0Offset] = uint64_to_double(state0); 294 array[kState1Offset] = uint64_to_double(state1); 295 return *typed_array; 296 } 297 } // namespace internal 298 } // namespace v8 299