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