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