blob: 6397ad15de9aaedff245e09a3c1356a701ace8c1 [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
5#include "src/v8.h"
6
7#include "src/arguments.h"
8#include "src/assembler.h"
9#include "src/codegen.h"
10#include "src/runtime/runtime-utils.h"
11#include "src/third_party/fdlibm/fdlibm.h"
12
13
14namespace 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);
37 uint64_t integer = double_to_uint64(x);
38 integer = (integer >> 32) & 0xFFFFFFFFu;
39 return *isolate->factory()->NewNumber(static_cast<int32_t>(integer));
40}
41
42
43RUNTIME_FUNCTION(Runtime_DoubleLo) {
44 HandleScope scope(isolate);
45 DCHECK(args.length() == 1);
46 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
47 return *isolate->factory()->NewNumber(
48 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
49}
50
51
52RUNTIME_FUNCTION(Runtime_ConstructDouble) {
53 HandleScope scope(isolate);
54 DCHECK(args.length() == 2);
55 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
56 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
57 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
58 return *isolate->factory()->NewNumber(uint64_to_double(result));
59}
60
61
62RUNTIME_FUNCTION(Runtime_RemPiO2) {
63 HandleScope handle_scope(isolate);
64 DCHECK(args.length() == 1);
65 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
66 Factory* factory = isolate->factory();
67 double y[2] = {0.0, 0.0};
68 int n = fdlibm::rempio2(x, y);
69 Handle<FixedArray> array = factory->NewFixedArray(3);
70 Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]);
71 Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]);
72 array->set(0, Smi::FromInt(n));
73 array->set(1, *y0);
74 array->set(2, *y1);
75 return *factory->NewJSArrayWithElements(array);
76}
77
78
79static const double kPiDividedBy4 = 0.78539816339744830962;
80
81
82RUNTIME_FUNCTION(Runtime_MathAtan2) {
83 HandleScope scope(isolate);
84 DCHECK(args.length() == 2);
85 isolate->counters()->math_atan2()->Increment();
86
87 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
88 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
89 double result;
90 if (std::isinf(x) && std::isinf(y)) {
91 // Make sure that the result in case of two infinite arguments
92 // is a multiple of Pi / 4. The sign of the result is determined
93 // by the first argument (x) and the sign of the second argument
94 // determines the multiplier: one or three.
95 int multiplier = (x < 0) ? -1 : 1;
96 if (y < 0) multiplier *= 3;
97 result = multiplier * kPiDividedBy4;
98 } else {
99 result = std::atan2(x, y);
100 }
101 return *isolate->factory()->NewNumber(result);
102}
103
104
105RUNTIME_FUNCTION(Runtime_MathExpRT) {
106 HandleScope scope(isolate);
107 DCHECK(args.length() == 1);
108 isolate->counters()->math_exp()->Increment();
109
110 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
111 lazily_initialize_fast_exp();
112 return *isolate->factory()->NewNumber(fast_exp(x));
113}
114
115
116RUNTIME_FUNCTION(Runtime_MathFloorRT) {
117 HandleScope scope(isolate);
118 DCHECK(args.length() == 1);
119 isolate->counters()->math_floor()->Increment();
120
121 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
122 return *isolate->factory()->NewNumber(Floor(x));
123}
124
125
126// Slow version of Math.pow. We check for fast paths for special cases.
127// Used if VFP3 is not available.
128RUNTIME_FUNCTION(Runtime_MathPowSlow) {
129 HandleScope scope(isolate);
130 DCHECK(args.length() == 2);
131 isolate->counters()->math_pow()->Increment();
132
133 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
134
135 // If the second argument is a smi, it is much faster to call the
136 // custom powi() function than the generic pow().
137 if (args[1]->IsSmi()) {
138 int y = args.smi_at(1);
139 return *isolate->factory()->NewNumber(power_double_int(x, y));
140 }
141
142 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
143 double result = power_helper(x, y);
144 if (std::isnan(result)) return isolate->heap()->nan_value();
145 return *isolate->factory()->NewNumber(result);
146}
147
148
149// Fast version of Math.pow if we know that y is not an integer and y is not
150// -0.5 or 0.5. Used as slow case from full codegen.
151RUNTIME_FUNCTION(Runtime_MathPowRT) {
152 HandleScope scope(isolate);
153 DCHECK(args.length() == 2);
154 isolate->counters()->math_pow()->Increment();
155
156 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
157 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
158 if (y == 0) {
159 return Smi::FromInt(1);
160 } else {
161 double result = power_double_double(x, y);
162 if (std::isnan(result)) return isolate->heap()->nan_value();
163 return *isolate->factory()->NewNumber(result);
164 }
165}
166
167
168RUNTIME_FUNCTION(Runtime_RoundNumber) {
169 HandleScope scope(isolate);
170 DCHECK(args.length() == 1);
171 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
172 isolate->counters()->math_round()->Increment();
173
174 if (!input->IsHeapNumber()) {
175 DCHECK(input->IsSmi());
176 return *input;
177 }
178
179 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
180
181 double value = number->value();
182 int exponent = number->get_exponent();
183 int sign = number->get_sign();
184
185 if (exponent < -1) {
186 // Number in range ]-0.5..0.5[. These always round to +/-zero.
187 if (sign) return isolate->heap()->minus_zero_value();
188 return Smi::FromInt(0);
189 }
190
191 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
192 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
193 // argument holds for 32-bit smis).
194 if (!sign && exponent < kSmiValueSize - 2) {
195 return Smi::FromInt(static_cast<int>(value + 0.5));
196 }
197
198 // If the magnitude is big enough, there's no place for fraction part. If we
199 // try to add 0.5 to this number, 1.0 will be added instead.
200 if (exponent >= 52) {
201 return *number;
202 }
203
204 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
205
206 // Do not call NumberFromDouble() to avoid extra checks.
207 return *isolate->factory()->NewNumber(Floor(value + 0.5));
208}
209
210
211RUNTIME_FUNCTION(Runtime_MathSqrtRT) {
212 HandleScope scope(isolate);
213 DCHECK(args.length() == 1);
214 isolate->counters()->math_sqrt()->Increment();
215
216 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
217 return *isolate->factory()->NewNumber(fast_sqrt(x));
218}
219
220
221RUNTIME_FUNCTION(Runtime_MathFround) {
222 HandleScope scope(isolate);
223 DCHECK(args.length() == 1);
224
225 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
226 float xf = DoubleToFloat32(x);
227 return *isolate->factory()->NewNumber(xf);
228}
229
230
231RUNTIME_FUNCTION(RuntimeReference_MathPow) {
232 SealHandleScope shs(isolate);
233 return __RT_impl_Runtime_MathPowSlow(args, isolate);
234}
235
236
237RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) {
238 SealHandleScope shs(isolate);
239 DCHECK(args.length() == 1);
240 CONVERT_ARG_CHECKED(Object, obj, 0);
241 if (!obj->IsHeapNumber()) return isolate->heap()->false_value();
242 HeapNumber* number = HeapNumber::cast(obj);
243 return isolate->heap()->ToBoolean(IsMinusZero(number->value()));
244}
245}
246} // namespace v8::internal