• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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