1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <math.h>
17
18 #include "ecma-alloc.h"
19 #include "ecma-builtins.h"
20 #include "ecma-conversion.h"
21 #include "ecma-exceptions.h"
22 #include "ecma-gc.h"
23 #include "ecma-globals.h"
24 #include "ecma-helpers.h"
25 #include "ecma-number-arithmetic.h"
26 #include "ecma-objects.h"
27 #include "ecma-objects-general.h"
28 #include "ecma-try-catch-macro.h"
29 #include "jrt.h"
30 #include "jrt-libc-includes.h"
31
32 #if defined (WIN32)
33 #include <intrin.h>
34 #endif
35
36 #if ENABLED (JERRY_BUILTIN_MATH)
37
38 #define ECMA_BUILTINS_INTERNAL
39 #include "ecma-builtins-internal.h"
40
41 /**
42 * This object has a custom dispatch function.
43 */
44 #define BUILTIN_CUSTOM_DISPATCH
45
46 /**
47 * List of built-in routine identifiers.
48 */
49 enum
50 {
51 ECMA_MATH_OBJECT_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
52
53 ECMA_MATH_OBJECT_ABS, /* ECMA-262 v5, 15.8.2.1 */
54 ECMA_MATH_OBJECT_ACOS, /* ECMA-262 v5, 15.8.2.2 */
55 ECMA_MATH_OBJECT_ASIN, /* ECMA-262 v5, 15.8.2.3 */
56 ECMA_MATH_OBJECT_ATAN, /* ECMA-262 v5, 15.8.2.4 */
57 ECMA_MATH_OBJECT_CEIL, /* ECMA-262 v5, 15.8.2.6 */
58 ECMA_MATH_OBJECT_COS, /* ECMA-262 v5, 15.8.2.7 */
59 ECMA_MATH_OBJECT_EXP, /* ECMA-262 v5, 15.8.2.8 */
60 ECMA_MATH_OBJECT_FLOOR, /* ECMA-262 v5, 15.8.2.9 */
61 ECMA_MATH_OBJECT_LOG, /* ECMA-262 v5, 15.8.2.10 */
62 ECMA_MATH_OBJECT_ROUND, /* ECMA-262 v5, 15.8.2.15 */
63 ECMA_MATH_OBJECT_SIN, /* ECMA-262 v5, 15.8.2.16 */
64 ECMA_MATH_OBJECT_SQRT, /* ECMA-262 v5, 15.8.2.17 */
65 ECMA_MATH_OBJECT_TAN, /* ECMA-262 v5, 15.8.2.18 */
66 #if ENABLED (JERRY_ES2015)
67 ECMA_MATH_OBJECT_ACOSH, /* ECMA-262 v6, 20.2.2.3 */
68 ECMA_MATH_OBJECT_ASINH, /* ECMA-262 v6, 20.2.2.5 */
69 ECMA_MATH_OBJECT_ATANH, /* ECMA-262 v6, 20.2.2.7 */
70 ECMA_MATH_OBJECT_CBRT, /* ECMA-262 v6, 20.2.2.9 */
71 ECMA_MATH_OBJECT_CLZ32, /* ECMA-262 v6, 20.2.2.11 */
72 ECMA_MATH_OBJECT_COSH, /* ECMA-262 v6, 20.2.2.13 */
73 ECMA_MATH_OBJECT_EXPM1, /* ECMA-262 v6, 20.2.2.15 */
74 ECMA_MATH_OBJECT_FROUND, /* ECMA-262 v6, 20.2.2.17 */
75 ECMA_MATH_OBJECT_LOG1P, /* ECMA-262 v6, 20.2.2.21 */
76 ECMA_MATH_OBJECT_LOG10, /* ECMA-262 v6, 20.2.2.22 */
77 ECMA_MATH_OBJECT_LOG2, /* ECMA-262 v6, 20.2.2.23 */
78 ECMA_MATH_OBJECT_SIGN, /* ECMA-262 v6, 20.2.2.29 */
79 ECMA_MATH_OBJECT_SINH, /* ECMA-262 v6, 20.2.2.31 */
80 ECMA_MATH_OBJECT_TANH, /* ECMA-262 v6, 20.2.2.34 */
81 ECMA_MATH_OBJECT_TRUNC, /* ECMA-262 v6, 20.2.2.35 */
82 #endif /* ENABLED (JERRY_ES2015) */
83 ECMA_MATH_OBJECT_ATAN2, /* ECMA-262 v5, 15.8.2.5 */ /* first routine with 2 arguments */
84 #if ENABLED (JERRY_ES2015)
85 ECMA_MATH_OBJECT_IMUL, /* ECMA-262 v6, 20.2.2.19 */
86 #endif /* ENABLED (JERRY_ES2015) */
87 ECMA_MATH_OBJECT_POW, /* ECMA-262 v5, 15.8.2.13 */ /* last routine with 1 or 2 arguments*/
88 ECMA_MATH_OBJECT_MAX, /* ECMA-262 v5, 15.8.2.11 */
89 ECMA_MATH_OBJECT_MIN, /* ECMA-262 v5, 15.8.2.12 */
90 #if ENABLED (JERRY_ES2015)
91 ECMA_MATH_OBJECT_HYPOT, /* ECMA-262 v6, 20.2.2.18 */
92 #endif /* ENABLED (JERRY_ES2015) */
93 ECMA_MATH_OBJECT_RANDOM, /* ECMA-262 v5, 15.8.2.14 */
94 };
95
96 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-math.inc.h"
97 #define BUILTIN_UNDERSCORED_ID math
98 #include "ecma-builtin-internal-routines-template.inc.h"
99
100 /** \addtogroup ecma ECMA
101 * @{
102 *
103 * \addtogroup ecmabuiltins
104 * @{
105 *
106 * \addtogroup object ECMA Object object built-in
107 * @{
108 */
109
110 /**
111 * The Math object's 'max' 'min' routines.
112 *
113 * See also:
114 * ECMA-262 v5, 15.8.2.11
115 * ECMA-262 v5, 15.8.2.12
116 *
117 * @return ecma value
118 * Returned value must be freed with ecma_free_value.
119 */
120 static ecma_value_t
ecma_builtin_math_object_max_min(bool is_max,const ecma_value_t * arg,ecma_length_t args_number)121 ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */
122 const ecma_value_t *arg, /**< arguments list */
123 ecma_length_t args_number) /**< number of arguments */
124 {
125 ecma_number_t result_num = ecma_number_make_infinity (is_max);
126 bool nan_found = false;
127
128 while (args_number > 0)
129 {
130 ecma_number_t arg_num;
131
132 if (ecma_is_value_number (*arg))
133 {
134 arg_num = ecma_get_number_from_value (*arg);
135 }
136 else
137 {
138 ecma_value_t value = ecma_op_to_number (*arg);
139
140 if (ECMA_IS_VALUE_ERROR (value))
141 {
142 return value;
143 }
144
145 arg_num = ecma_get_number_from_value (value);
146
147 ecma_fast_free_value (value);
148 }
149
150 arg++;
151 args_number--;
152
153 if (JERRY_UNLIKELY (nan_found || ecma_number_is_nan (arg_num)))
154 {
155 nan_found = true;
156 continue;
157 }
158
159 if (ecma_number_is_zero (arg_num)
160 && ecma_number_is_zero (result_num))
161 {
162 bool is_negative = ecma_number_is_negative (arg_num);
163
164 if (is_max ? !is_negative : is_negative)
165 {
166 result_num = arg_num;
167 }
168 }
169 else
170 {
171 if (is_max ? (arg_num > result_num) : (arg_num < result_num))
172 {
173 result_num = arg_num;
174 }
175 }
176 }
177
178 if (JERRY_UNLIKELY (nan_found))
179 {
180 result_num = ecma_number_make_nan ();
181 }
182
183 return ecma_make_number_value (result_num);
184 } /* ecma_builtin_math_object_max_min */
185
186 #if ENABLED (JERRY_ES2015)
187 /**
188 * The Math object's 'hypot' routine
189 *
190 * See also:
191 * ECMA-262 v6, 20.2.2.18
192 *
193 * @return ecma value
194 * Returned value must be freed with ecma_free_value.
195 */
196 static ecma_value_t
ecma_builtin_math_object_hypot(const ecma_value_t * arg,ecma_length_t args_number)197 ecma_builtin_math_object_hypot (const ecma_value_t *arg, /**< arguments list */
198 ecma_length_t args_number) /**< number of arguments */
199 {
200 if (args_number == 0)
201 {
202 return ecma_make_number_value (0.0);
203 }
204
205 bool nan_found = false;
206 bool inf_found = false;
207 ecma_number_t result_num = 0;
208
209 while (args_number > 0)
210 {
211 ecma_number_t arg_num;
212 if (ecma_is_value_number (*arg))
213 {
214 arg_num = ecma_get_number_from_value (*arg);
215 }
216 else
217 {
218 ecma_value_t value = ecma_op_to_number (*arg);
219 if (ECMA_IS_VALUE_ERROR (value))
220 {
221 return value;
222 }
223 arg_num = ecma_get_number_from_value (value);
224 ecma_fast_free_value (value);
225 }
226
227 arg++;
228 args_number--;
229
230 if (JERRY_UNLIKELY (inf_found || ecma_number_is_infinity (arg_num)))
231 {
232 inf_found = true;
233 continue;
234 }
235
236 if (JERRY_UNLIKELY (nan_found || ecma_number_is_nan (arg_num)))
237 {
238 nan_found = true;
239 continue;
240 }
241
242 result_num += arg_num * arg_num;
243 }
244
245 if (JERRY_UNLIKELY (inf_found))
246 {
247 return ecma_make_number_value (ecma_number_make_infinity (false));
248 }
249
250 if (JERRY_UNLIKELY (nan_found))
251 {
252 return ecma_make_nan_value ();
253 }
254
255 return ecma_make_number_value (sqrt (result_num));
256 } /* ecma_builtin_math_object_hypot */
257
258 /**
259 * The Math object's 'trunc' routine
260 *
261 * See also:
262 * ECMA-262 v6, 20.2.2.35
263 *
264 * @return ecma number
265 */
266 static ecma_number_t
ecma_builtin_math_object_trunc(ecma_number_t arg)267 ecma_builtin_math_object_trunc (ecma_number_t arg)
268 {
269 if (ecma_number_is_nan (arg) || ecma_number_is_infinity (arg) || ecma_number_is_zero (arg))
270 {
271 return arg;
272 }
273
274 if ((arg > 0) && (arg < 1))
275 {
276 return (ecma_number_t) 0.0;
277 }
278
279 if ((arg < 0) && (arg > -1))
280 {
281 return (ecma_number_t) -0.0;
282 }
283
284 return (ecma_number_t) arg - fmod (arg, 1);
285 } /* ecma_builtin_math_object_trunc */
286
287 /**
288 * The Math object's 'sign' routine
289 *
290 * See also:
291 * ECMA-262 v6, 20.2.2.29
292 *
293 * @return ecma number
294 */
295 static ecma_number_t
ecma_builtin_math_object_sign(ecma_number_t arg)296 ecma_builtin_math_object_sign (ecma_number_t arg)
297 {
298 if (ecma_number_is_nan (arg) || ecma_number_is_zero (arg))
299 {
300 return arg;
301 }
302
303 if (ecma_number_is_negative (arg))
304 {
305 return (ecma_number_t) -1.0;
306 }
307
308 return (ecma_number_t) 1.0;
309 } /* ecma_builtin_math_object_sign */
310
311 #endif /* ENABLED (JERRY_ES2015) */
312
313 /**
314 * The Math object's 'random' routine.
315 *
316 * See also:
317 * ECMA-262 v5, 15.8.2.14
318 *
319 * @return ecma value
320 * Returned value must be freed with ecma_free_value.
321 */
322 static ecma_value_t
ecma_builtin_math_object_random(void)323 ecma_builtin_math_object_random (void)
324 {
325 const ecma_number_t rand_max = (ecma_number_t) RAND_MAX;
326 const ecma_number_t rand_max_min_1 = (ecma_number_t) (RAND_MAX - 1);
327
328 return ecma_make_number_value (((ecma_number_t) rand ()) / rand_max * rand_max_min_1 / rand_max);
329 } /* ecma_builtin_math_object_random */
330
331 /**
332 * Dispatcher for the built-in's routines.
333 *
334 * @return ecma value
335 * Returned value must be freed with ecma_free_value.
336 */
337 ecma_value_t
ecma_builtin_math_dispatch_routine(uint16_t builtin_routine_id,ecma_value_t this_arg,const ecma_value_t arguments_list[],ecma_length_t arguments_number)338 ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine
339 * identifier */
340 ecma_value_t this_arg, /**< 'this' argument value */
341 const ecma_value_t arguments_list[], /**< list of arguments
342 * passed to routine */
343 ecma_length_t arguments_number) /**< length of arguments' list */
344 {
345 JERRY_UNUSED (this_arg);
346
347 if (builtin_routine_id <= ECMA_MATH_OBJECT_POW)
348 {
349 ecma_number_t x = ecma_number_make_nan ();
350 ecma_number_t y = ecma_number_make_nan ();
351
352 if (arguments_number >= 1)
353 {
354 if (ecma_is_value_number (arguments_list[0]))
355 {
356 x = ecma_get_number_from_value (arguments_list[0]);
357 }
358 else
359 {
360 ecma_value_t value = ecma_op_to_number (arguments_list[0]);
361
362 if (ECMA_IS_VALUE_ERROR (value))
363 {
364 return value;
365 }
366
367 x = ecma_get_number_from_value (value);
368
369 ecma_fast_free_value (value);
370 }
371 }
372
373 if (builtin_routine_id >= ECMA_MATH_OBJECT_ATAN2
374 && arguments_number >= 2)
375 {
376 if (ecma_is_value_number (arguments_list[1]))
377 {
378 y = ecma_get_number_from_value (arguments_list[1]);
379 }
380 else
381 {
382 ecma_value_t value = ecma_op_to_number (arguments_list[1]);
383
384 if (ECMA_IS_VALUE_ERROR (value))
385 {
386 return value;
387 }
388
389 y = ecma_get_number_from_value (value);
390
391 ecma_fast_free_value (value);
392 }
393 }
394
395 switch (builtin_routine_id)
396 {
397 case ECMA_MATH_OBJECT_ABS:
398 {
399 x = DOUBLE_TO_ECMA_NUMBER_T (fabs (x));
400 break;
401 }
402 case ECMA_MATH_OBJECT_ACOS:
403 {
404 x = DOUBLE_TO_ECMA_NUMBER_T (acos (x));
405 break;
406 }
407 case ECMA_MATH_OBJECT_ASIN:
408 {
409 x = DOUBLE_TO_ECMA_NUMBER_T (asin (x));
410 break;
411 }
412 case ECMA_MATH_OBJECT_ATAN:
413 {
414 x = DOUBLE_TO_ECMA_NUMBER_T (atan (x));
415 break;
416 }
417 case ECMA_MATH_OBJECT_CEIL:
418 {
419 x = DOUBLE_TO_ECMA_NUMBER_T (ceil (x));
420 break;
421 }
422 case ECMA_MATH_OBJECT_COS:
423 {
424 x = DOUBLE_TO_ECMA_NUMBER_T (cos (x));
425 break;
426 }
427 case ECMA_MATH_OBJECT_EXP:
428 {
429 x = DOUBLE_TO_ECMA_NUMBER_T (exp (x));
430 break;
431 }
432 case ECMA_MATH_OBJECT_FLOOR:
433 {
434 x = DOUBLE_TO_ECMA_NUMBER_T (floor (x));
435 break;
436 }
437 case ECMA_MATH_OBJECT_LOG:
438 {
439 x = DOUBLE_TO_ECMA_NUMBER_T (log (x));
440 break;
441 }
442 #if ENABLED (JERRY_ES2015)
443 case ECMA_MATH_OBJECT_TRUNC:
444 {
445 x = ecma_builtin_math_object_trunc (x);
446 break;
447 }
448 case ECMA_MATH_OBJECT_SIGN:
449 {
450 x = ecma_builtin_math_object_sign (x);
451 break;
452 }
453 #endif /* ENABLED (JERRY_ES2015) */
454 case ECMA_MATH_OBJECT_ROUND:
455 {
456 if (ecma_number_is_nan (x)
457 || ecma_number_is_zero (x)
458 || ecma_number_is_infinity (x)
459 || fmod (x, 1.0) == 0)
460 {
461 /* Do nothing. */
462 }
463 else if (ecma_number_is_negative (x)
464 && x >= -ECMA_NUMBER_HALF)
465 {
466 x = -ECMA_NUMBER_ZERO;
467 }
468 else
469 {
470 const ecma_number_t up_half = x + ECMA_NUMBER_HALF;
471 const ecma_number_t down_half = x - ECMA_NUMBER_HALF;
472 const ecma_number_t up_rounded = up_half - ecma_op_number_remainder (up_half, ECMA_NUMBER_ONE);
473 const ecma_number_t down_rounded = down_half - ecma_op_number_remainder (down_half, ECMA_NUMBER_ONE);
474
475 if (up_rounded - x <= x - down_rounded)
476 {
477 x = up_rounded;
478 }
479 else
480 {
481 x = down_rounded;
482 }
483 }
484 break;
485 }
486 case ECMA_MATH_OBJECT_SIN:
487 {
488 x = DOUBLE_TO_ECMA_NUMBER_T (sin (x));
489 break;
490 }
491 case ECMA_MATH_OBJECT_SQRT:
492 {
493 x = DOUBLE_TO_ECMA_NUMBER_T (sqrt (x));
494 break;
495 }
496 case ECMA_MATH_OBJECT_TAN:
497 {
498 x = DOUBLE_TO_ECMA_NUMBER_T (tan (x));
499 break;
500 }
501 case ECMA_MATH_OBJECT_ATAN2:
502 {
503 x = DOUBLE_TO_ECMA_NUMBER_T (atan2 (x, y));
504 break;
505 }
506 case ECMA_MATH_OBJECT_POW:
507 {
508 x = ecma_number_pow (x, y);
509 break;
510 }
511 #if ENABLED (JERRY_ES2015)
512 case ECMA_MATH_OBJECT_ACOSH:
513 {
514 x = DOUBLE_TO_ECMA_NUMBER_T (acosh (x));
515 break;
516 }
517 case ECMA_MATH_OBJECT_ASINH:
518 {
519 x = DOUBLE_TO_ECMA_NUMBER_T (asinh (x));
520 break;
521 }
522 case ECMA_MATH_OBJECT_ATANH:
523 {
524 x = DOUBLE_TO_ECMA_NUMBER_T (atanh (x));
525 break;
526 }
527 case ECMA_MATH_OBJECT_CBRT:
528 {
529 x = DOUBLE_TO_ECMA_NUMBER_T (cbrt (x));
530 break;
531 }
532 case ECMA_MATH_OBJECT_COSH:
533 {
534 x = DOUBLE_TO_ECMA_NUMBER_T (cosh (x));
535 break;
536 }
537 case ECMA_MATH_OBJECT_EXPM1:
538 {
539 x = DOUBLE_TO_ECMA_NUMBER_T (expm1 (x));
540 break;
541 }
542 case ECMA_MATH_OBJECT_LOG1P:
543 {
544 x = DOUBLE_TO_ECMA_NUMBER_T (log1p (x));
545 break;
546 }
547 case ECMA_MATH_OBJECT_LOG10:
548 {
549 x = DOUBLE_TO_ECMA_NUMBER_T (log10 (x));
550 break;
551 }
552 case ECMA_MATH_OBJECT_LOG2:
553 {
554 x = DOUBLE_TO_ECMA_NUMBER_T (log2 (x));
555 break;
556 }
557 case ECMA_MATH_OBJECT_SINH:
558 {
559 x = DOUBLE_TO_ECMA_NUMBER_T (sinh (x));
560 break;
561 }
562 case ECMA_MATH_OBJECT_TANH:
563 {
564 x = DOUBLE_TO_ECMA_NUMBER_T (tanh (x));
565 break;
566 }
567 case ECMA_MATH_OBJECT_CLZ32:
568 {
569 uint32_t n = ecma_number_to_uint32 (x);
570 #if defined (__GNUC__) || defined (__clang__)
571 x = n ? __builtin_clz (n) : 32;
572 #elif defined (WIN32)
573 unsigned long ret;
574 x = _BitScanReverse (&ret, n) ? 31 - ret : 32;
575 #else
576 x = 32;
577 for (int i = 31; i >= 0; i--)
578 {
579 if (n >> i)
580 {
581 x = 31 - i;
582 break;
583 }
584 }
585 #endif
586 break;
587 }
588 case ECMA_MATH_OBJECT_FROUND:
589 {
590 x = (float) x;
591 break;
592 }
593 case ECMA_MATH_OBJECT_IMUL:
594 {
595 x = (int32_t) (ecma_number_to_uint32 (x) * ecma_number_to_uint32 (y));
596 break;
597 }
598 #endif /* ENABLED (JERRY_ES2015) */
599 }
600 return ecma_make_number_value (x);
601 } /* if (builtin_routine_id <= ECMA_MATH_OBJECT_POW) */
602
603 if (builtin_routine_id <= ECMA_MATH_OBJECT_MIN)
604 {
605 return ecma_builtin_math_object_max_min (builtin_routine_id == ECMA_MATH_OBJECT_MAX,
606 arguments_list,
607 arguments_number);
608 }
609
610 #if ENABLED (JERRY_ES2015)
611 if (builtin_routine_id == ECMA_MATH_OBJECT_HYPOT)
612 {
613 return ecma_builtin_math_object_hypot (arguments_list, arguments_number);
614 }
615 #endif /* ENABLED (JERRY_ES2015) */
616
617 JERRY_ASSERT (builtin_routine_id == ECMA_MATH_OBJECT_RANDOM);
618
619 return ecma_builtin_math_object_random ();
620 } /* ecma_builtin_math_dispatch_routine */
621
622 /**
623 * @}
624 * @}
625 * @}
626 */
627
628 #endif /* ENABLED (JERRY_BUILTIN_MATH) */
629