blob: 427d2b868a639df4f52a47cb384eb6fa49cdf862 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
8#include "src/assembler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/base/utils/random-number-generator.h"
10#include "src/bootstrapper.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/codegen.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/third_party/fdlibm/fdlibm.h"
13
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014namespace v8 {
15namespace 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
26RUNTIME_UNARY_MATH(Acos, acos)
27RUNTIME_UNARY_MATH(Asin, asin)
28RUNTIME_UNARY_MATH(Atan, atan)
29RUNTIME_UNARY_MATH(LogRT, log)
30#undef RUNTIME_UNARY_MATH
31
32
33RUNTIME_FUNCTION(Runtime_DoubleHi) {
34 HandleScope scope(isolate);
35 DCHECK(args.length() == 1);
36 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 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);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040041}
42
43
44RUNTIME_FUNCTION(Runtime_DoubleLo) {
45 HandleScope scope(isolate);
46 DCHECK(args.length() == 1);
47 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 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);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040052}
53
54
55RUNTIME_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
65RUNTIME_FUNCTION(Runtime_RemPiO2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066 SealHandleScope shs(isolate);
67 DisallowHeapAllocation no_gc;
68 DCHECK(args.length() == 2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040069 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 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));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040075}
76
77
78static const double kPiDividedBy4 = 0.78539816339744830962;
79
80
81RUNTIME_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
104RUNTIME_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);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 lazily_initialize_fast_exp(isolate);
111 return *isolate->factory()->NewNumber(fast_exp(x, isolate));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400112}
113
114
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115RUNTIME_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
126RUNTIME_FUNCTION(Runtime_MathFloor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400127 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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138RUNTIME_FUNCTION(Runtime_MathPow) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139 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);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 double result = power_helper(isolate, x, y);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 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.
161RUNTIME_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
178RUNTIME_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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221RUNTIME_FUNCTION(Runtime_MathSqrt) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 HandleScope scope(isolate);
223 DCHECK(args.length() == 1);
224 isolate->counters()->math_sqrt()->Increment();
225
226 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 lazily_initialize_fast_sqrt(isolate);
228 return *isolate->factory()->NewNumber(fast_sqrt(x, isolate));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229}
230
231
232RUNTIME_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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242RUNTIME_FUNCTION(Runtime_IsMinusZero) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250
251
252RUNTIME_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;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400296}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297} // namespace internal
298} // namespace v8