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 */
49enum
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 */
120static ecma_value_t
121ecma_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 */
196static ecma_value_t
197ecma_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 */
266static ecma_number_t
267ecma_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 */
295static ecma_number_t
296ecma_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 */
322static ecma_value_t
323ecma_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 */
337ecma_value_t
338ecma_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