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 
RUNTIME_UNARY_MATH(Acos,acos)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 
RUNTIME_FUNCTION(Runtime_DoubleLo)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 
RUNTIME_FUNCTION(Runtime_ConstructDouble)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 
RUNTIME_FUNCTION(Runtime_RemPiO2)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 
RUNTIME_FUNCTION(Runtime_MathAtan2)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 
RUNTIME_FUNCTION(Runtime_MathExpRT)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 
RUNTIME_FUNCTION(Runtime_MathClz32)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 
RUNTIME_FUNCTION(Runtime_MathFloor)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.
RUNTIME_FUNCTION(Runtime_MathPow)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.
RUNTIME_FUNCTION(Runtime_MathPowRT)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 
RUNTIME_FUNCTION(Runtime_RoundNumber)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 
RUNTIME_FUNCTION(Runtime_MathSqrt)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 
RUNTIME_FUNCTION(Runtime_MathFround)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 
RUNTIME_FUNCTION(Runtime_IsMinusZero)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 
RUNTIME_FUNCTION(Runtime_GenerateRandomNumbers)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